_CODE_ACCESS int remove_device(char *name) { _DEVICE *ptr; /*-------------------------------------------------------------------------*/ /* FIND RECORD AND SET NAME TO NULL */ /*-------------------------------------------------------------------------*/ /* CRITICAL REGION PROTECTS ACCESS TO _device[] */ /*-------------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_DEVICE_TBL); if (!(ptr = finddevice(name))) { __TI_data_synch_INV(&_device, sizeof(_device)); __TI_resource_unlock(__TI_LOCK_DEVICE_TBL); return -1; } ptr->name[0] = '\0'; __TI_data_synch_WBINV(&_device, sizeof(_device)); __TI_resource_unlock(__TI_LOCK_DEVICE_TBL); return 0; }
_CODE_ACCESS int rename(const char *old_name, const char *new_name) { _DEVICE *old_dev, *new_dev; int result; /*------------------------------------------------------------------------*/ /* CRITICAL REGION PROTECTS _device[] ACCESS THAT OCCURS IN getdevice() */ /* (see file header comment for more on mutex and data coherence). */ /*------------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_DEVICE_TBL); old_dev = getdevice(&old_name); new_dev = getdevice(&new_name); /*------------------------------------------------------------------------*/ /* IF THE DEVICES ARE NOT THE SAME, RENAME WOULD REQUIRE A FILE COPY. */ /*------------------------------------------------------------------------*/ if (old_dev != new_dev) { __TI_data_synch_INV(&_device, sizeof(_device)); __TI_resource_unlock(__TI_LOCK_DEVICE_TBL); return -1; } /*------------------------------------------------------------------------*/ /* CALL FUNCTION FROM DEVICE TABLE TO PERFORM RENAME FOR THIS DEVICE/FILE */ /*------------------------------------------------------------------------*/ result = (*(old_dev->RENAME)) (old_name, new_name); __TI_data_synch_INV(&_device, sizeof(_device)); __TI_resource_unlock(__TI_LOCK_DEVICE_TBL); return result; }
_CODE_ACCESS int close(int llv_fd) { int result; #if defined(__TI_SHARED_DATA_SYNCHRONIZATION) _DEVICE *dev_ptr = NULL; #endif if (llv_fd < 0 || llv_fd >= _NSTREAM) return -1; /*------------------------------------------------------------------------*/ /* CALL FUNCTION FROM DEVICE TABLE TO PERFORM CLOSE FOR THIS DEVICE/FILE */ /* CLEAR STREAM TABLE ENTRY AND DEVICE FLAGS */ /*------------------------------------------------------------------------*/ /* CRITICAL REGION PROTECTS ACCESS TO _stream[] (see file header comment).*/ /*------------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_STREAM_TBL); if (_stream[llv_fd].dev == NULL) { __TI_data_synch_INV(&_stream[llv_fd], sizeof(_stream[llv_fd])); __TI_resource_unlock(__TI_LOCK_STREAM_TBL); return -1; } /*------------------------------------------------------------------------*/ /* We'll need to invalidate the device table entry that has the address */ /* of the CLOSE function in it, so hold on to its address. We guard the */ /* definition of dev_ptr here to avoid a "set but never refed" compile */ /* time error when building the RTS in a config that doesn't have shared */ /* data synchronization turned on. */ /*------------------------------------------------------------------------*/ #if defined(__TI_SHARED_DATA_SYNCHRONIZATION) dev_ptr = _stream[llv_fd].dev; #endif if ( (result = (*(_stream[llv_fd].dev->CLOSE))(_stream[llv_fd].dfd)) != -1 ) { _stream[llv_fd].dev->flags &= ~_BUSY; _stream[llv_fd].dev = NULL; } /*------------------------------------------------------------------------*/ /* Invalidate both the device table entry that was referenced and the */ /* stream table entry associated with the input file descriptor (llv_fd). */ /* It is possible (though unlikely) that the contents of the device table */ /* entry and/or the stream table entry could be updated by another thread */ /* before this thread accesses either of those objects again. */ /*------------------------------------------------------------------------*/ /* For the address of the device table entry, we use a copy of */ /* _stream[llv_fd].dev (dev_ptr) that was made before _stream[llv_fd].dev */ /* gets modified in the above if block. */ /*------------------------------------------------------------------------*/ __TI_data_synch_INV(dev_ptr, sizeof(_DEVICE)); __TI_data_synch_WBINV(&_stream[llv_fd], sizeof(_stream[llv_fd])); __TI_resource_unlock(__TI_LOCK_STREAM_TBL); return result; }
_CODE_ACCESS FILE *tmpfile(void) { char tfname[L_tmpnam]; FILE *_fp = NULL; if (tmpnam(tfname)) _fp = fopen(tfname, "wb+"); /*------------------------------------------------------------------------*/ /* A non-NULL _fp returned from fopen() is assumed to be a pointer to a */ /* file stream which is a shared resource. */ /*------------------------------------------------------------------------*/ /* The current thread in a multi-threaded application must protect access */ /* to the file stream and __TI_tmpnams[]. In this case, _fp will be */ /* updated, so we must ensure that the local copy of _fp and _tmpnams[] */ /* are flushed to shared memory before leaving the critical section */ /* (invalidated if it is not modified). */ /*------------------------------------------------------------------------*/ if (_fp) { __TI_file_lock(_fp); _SET(_fp, _TMPFILE); __TI_resource_lock(__TI_LOCK_TMPNAMS); strcpy(__TI_tmpnams[_fp->fd], tfname); __TI_data_synch_WBINV(&__TI_tmpnams[_fp->fd], L_tmpnam); __TI_data_synch_WBINV(_fp, sizeof(FILE)); __TI_resource_unlock(__TI_LOCK_TMPNAMS); __TI_file_unlock(_fp); } return (_fp); }
_CODE_ACCESS int HOSTread(int dev_fd, char *buf, unsigned count) { int result; /*-----------------------------------------------------------------------*/ /* CRITICAL REGION TO PROTECT ACCESSES TO parmbuf[] AND _CIOBUF_ (see */ /* file header comment above for more about mutexes and data coherency). */ /*-----------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_HOST_CIO); if (count > BUFSIZ) count = BUFSIZ; LOADSHORT(parmbuf,dev_fd,0); LOADSHORT(parmbuf,count,2); __TI_writemsg(_DTREAD,parmbuf,NULL,0); __TI_readmsg(parmbuf,buf); result = UNLOADSHORT(parmbuf,0); __TI_data_synch_WBINV(&parmbuf, sizeof(parmbuf)); __TI_resource_unlock(__TI_LOCK_HOST_CIO); return result; }
_CODE_ACCESS void __TI_buff_read(FILE *_fp) { /*------------------------------------------------------------------------*/ /* Local variables */ /*------------------------------------------------------------------------*/ int errchk, j, buffer_size = _fp->bufend - _fp->buf; /*------------------------------------------------------------------------*/ /* If this is a line buffered stream, flush all line buffered streams. */ /* The current thread in a multi-threaded application must protect access */ /* to __TI_LOCK_FILE_TBL shared resources (_ftable[] and __TI_ft_end) and */ /* each file stream that is flushed. Ensure that the local copy of */ /* _ftable[] is flushed to shared memory and the local copy of */ /* __TI_ft_end is invalidated before leaving the critical section. */ /*------------------------------------------------------------------------*/ if (_BUFFMODE(_fp) == _IOLBF) { __TI_resource_lock(__TI_LOCK_FILE_TBL); for (j=0; j < __TI_ft_end; j++) if (_BUFFMODE(&_ftable[j]) == _IOLBF) { __TI_file_lock(&_ftable[j]); __TI_doflush(&_ftable[j]); __TI_data_synch_WBINV(&_ftable[j], sizeof(FILE)); __TI_file_unlock(&_ftable[j]); } __TI_data_synch_WBINV(&_ftable, sizeof(_ftable)); __TI_data_synch_INV(&__TI_ft_end, sizeof(__TI_ft_end)); __TI_resource_unlock(__TI_LOCK_FILE_TBL); } /*------------------------------------------------------------------------*/ /* Read in the next characters from the file. */ /*------------------------------------------------------------------------*/ errchk = read(_fp->fd, (char *)_fp->buf, buffer_size); /*------------------------------------------------------------------------*/ /* Adjust the buffer pointers. */ /*------------------------------------------------------------------------*/ _fp->buff_stop = _fp->buf + errchk; _fp->pos = _fp->buf; /*------------------------------------------------------------------------*/ /* Set any error flags if necessary. */ /*------------------------------------------------------------------------*/ switch (errchk) { case -1 : _SET(_fp, _STATERR); break; case 0 : _SET(_fp, _STATEOF); break; } return; }
_CODE_ACCESS char *tmpnam(char *_s) { /*------------------------------------------------------------------------*/ /* Local variables */ /*------------------------------------------------------------------------*/ int fd; __TI_resource_lock(__TI_LOCK_TMPNAM_COUNTER); /*------------------------------------------------------------------------*/ /* Get a filename from _GETNAME */ /*------------------------------------------------------------------------*/ _getname(counter++, tfname); /*------------------------------------------------------------------------*/ /* Check to see if the filename exists. Keep getting filenames until */ /* a unique one is found, or this function has reached its limit. */ /*------------------------------------------------------------------------*/ while (((fd=open(tfname, O_RDONLY, 0666)) >= 0) && (counter < TMP_MAX)) { close(fd); _getname(counter++, tfname); } if (counter >= TMP_MAX) { __TI_data_synch_WBINV(&counter, sizeof(counter)); __TI_resource_unlock(__TI_LOCK_TMPNAM_COUNTER); return (NULL); } __TI_data_synch_WBINV(&counter, sizeof(counter)); __TI_resource_unlock(__TI_LOCK_TMPNAM_COUNTER); /*------------------------------------------------------------------------*/ /* If _S is not NULL, store the new filename in it. */ /*------------------------------------------------------------------------*/ if (_s) { strcpy(_s, tfname); return (_s); } return (tfname); }
_CODE_ACCESS FILE *fopen(const char *_fname, const char *_mode) { FILE *f; /*-----------------------------------------------------------------------*/ /* This is a critical section because search_fp looks for a new file */ /* slot in the global table _ftable. */ /*-----------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_FILE_TBL); f = _openfile(_fname, _search_fp(), _mode); __TI_data_synch_WBINV(&_ftable, sizeof(_ftable)); __TI_resource_unlock(__TI_LOCK_FILE_TBL); return f; }
_CODE_ACCESS void srand(unsigned seed) { /*---------------------------------------------------------------------*/ /* To maintain backwards compatibility with releases that do not use */ /* TLS, we use a mutex lock to protect accesses to the variable 'next'.*/ /*---------------------------------------------------------------------*/ #if !defined(__TI_USE_TLS) __TI_resource_lock(__TI_LOCK_RAND); #endif next = seed; #if !defined(__TI_USE_TLS) __TI_resource_unlock(__TI_LOCK_RAND); #endif }
int atexit(void (*fun)()) { int err_code = 1; /*-----------------------------------------------------------------------*/ /* For multi-threaded applications, access to shared resources must be */ /* protected. In this case, both atexit_func_count and atexit_func[] are */ /* shared resources that may be accessed and updated by this function. */ /* Use the __TI_LOCK_ATEXIT mutex to create a critical section and */ /* that the local copies of both atexit_func_count and atexit_func[] are */ /* flushed to shared memory. */ /*-----------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_ATEXIT); /*-----------------------------------------------------------------------*/ /* We allow MAX_ATEXIT_FUN calls to atexit(); see the comment above the */ /* definition of MAX_ATEXIT_FUN for more details. BIOS has a specific */ /* request that we NOT use malloc here. If anyone requires additional */ /* atexit calls for use by RTS or OS, then the MAX_ATEXIT_FUN limit */ /* (above) must be adjusted and the library rebuilt (CQ20012, CQ20600). */ /*-----------------------------------------------------------------------*/ if (atexit_func_count < MAX_ATEXIT_FUN) { /*--------------------------------------------------------------------*/ /* Choose the next available entry for registering atexit functions. */ /*--------------------------------------------------------------------*/ int allocated_entry = atexit_func_count++; /*--------------------------------------------------------------------*/ /* Populate the allocated entry with the necessary details. */ /*--------------------------------------------------------------------*/ atexit_func[allocated_entry].next = NULL; atexit_func[allocated_entry].object = &__atexit_func_id__; atexit_func[allocated_entry].fun.dfun = fun; /*--------------------------------------------------------------------*/ /* Register the atexit function for processing at exit. */ /*--------------------------------------------------------------------*/ __add_dtor(&(atexit_func[allocated_entry])); err_code = 0; } __TI_data_synch_WBINV(&atexit_func_count, sizeof(int)); __TI_data_synch_WBINV(&atexit_func, sizeof(atexit_func)); __TI_resource_unlock(__TI_LOCK_ATEXIT); return err_code; }
_CODE_ACCESS FILE *freopen(const char *_fname, const char *_mode, register FILE *_fp) { FILE *f; /*-----------------------------------------------------------------------*/ /* This is a critical section because it expects the same slot in the */ /* global table _ftable to be available. */ /*-----------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_FILE_TBL); _closefile(_fp); f = _openfile(_fname, _fp, _mode); __TI_data_synch_WBINV(&_ftable, sizeof(_ftable)); __TI_resource_unlock(__TI_LOCK_FILE_TBL); return f; }
_CODE_ACCESS int fflush(register FILE *_fp) { int result = 0; /*------------------------------------------------------------------------*/ /* The current thread in a multi-threaded application must protect access */ /* to __TI_LOCK_FILE_TBL shared resources (_ftable[], __TI_ft_end, init */ /* and __TI_cleanup_ptr. init is a static local in __TI_search_fp() in */ /* fopen.c). In this case, __TI_doflush will update the specified file */ /* streams, so we must also protect access to the streams. */ /* The below loop will cache a local copy of _ftable[] and __TI_ft_end. */ /* Ensure that the local copy of _ftable[] and each flushed file stream */ /* is flushed to shared memory and the local copy of __TI_ft_end is */ /* invalidated before leaving the critical section. */ /*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/ /* If _fp is not a NULL pointer, call __TI_doflush for that stream. */ /* Otherwise, call __TI_doflush for all file streams in the table that are*/ /* active. */ /*------------------------------------------------------------------------*/ if (_fp) { __TI_file_lock(_fp); result = __TI_doflush(_fp); __TI_data_synch_WBINV(_fp, sizeof(FILE)); __TI_file_unlock(_fp); } else { int index; __TI_resource_lock(__TI_LOCK_FILE_TBL); for(index = 0; index < __TI_ft_end; index++) if(_ftable[index].fd != -1) { __TI_file_lock(&_ftable[index]); result |= __TI_doflush(&_ftable[index]); __TI_data_synch_WBINV(&_ftable[index], sizeof(_ftable[index])); __TI_file_unlock(&_ftable[index]); } __TI_data_synch_WBINV(&_ftable, sizeof(_ftable)); __TI_data_synch_INV(&__TI_ft_end, sizeof(__TI_ft_end)); __TI_resource_unlock(__TI_LOCK_FILE_TBL); } return (result); }
_CODE_ACCESS int rand(void) { int r; /*---------------------------------------------------------------------*/ /* To maintain backwards compatibility with releases that do not use */ /* TLS, we use a mutex lock to protect accesses to the variable 'next'.*/ /*---------------------------------------------------------------------*/ #if !defined(__TI_USE_TLS) __TI_resource_lock(__TI_LOCK_RAND); #endif next = next * 1103515245 + 12345; r = (int)((next/65536) % ((unsigned long)RAND_MAX + 1)); #if !defined(__TI_USE_TLS) __TI_resource_unlock(__TI_LOCK_RAND); #endif return r; }
_CODE_ACCESS int HOSTunlink(const char *path) { int result; /*-----------------------------------------------------------------------*/ /* CRITICAL REGION TO PROTECT ACCESSES TO parmbuf[] AND _CIOBUF_ (see */ /* file header comment above for more about mutexes and data coherency). */ /*-----------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_HOST_CIO); __TI_writemsg(_DTUNLINK,parmbuf,(char *)path,strlen(path) + 1); __TI_readmsg(parmbuf,NULL); result = UNLOADSHORT(parmbuf,0); __TI_data_synch_WBINV(&parmbuf, sizeof(parmbuf)); __TI_resource_unlock(__TI_LOCK_HOST_CIO); return result; }
_CODE_ACCESS int HOSTclose(int dev_fd) { int result; /*-----------------------------------------------------------------------*/ /* CRITICAL REGION TO PROTECT ACCESSES TO parmbuf[] AND _CIOBUF_ (see */ /* file header comment above for more about mutexes and data coherency). */ /*-----------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_HOST_CIO); LOADSHORT(parmbuf,dev_fd,0); __TI_writemsg(_DTCLOSE,parmbuf,NULL,0); __TI_readmsg(parmbuf,NULL); result = UNLOADSHORT(parmbuf,0); __TI_data_synch_WBINV(&parmbuf, sizeof(parmbuf)); __TI_resource_unlock(__TI_LOCK_HOST_CIO); return result; }
_CODE_ACCESS int unlink(const char *path) { _DEVICE *dev; int result; /*------------------------------------------------------------------------*/ /* GET A DEVICE AND CALL FUNCTION FROM DEVICE TABLE TO PERFORM UNLINK */ /* FOR THIS DEVICE/FILE */ /*------------------------------------------------------------------------*/ /* CRITICAL REGION PROTECTS _device[] ACCESS THAT OCCURS IN getdevice() */ /* (see file header comment for more on mutex and data coherence). */ /*------------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_DEVICE_TBL); dev = getdevice(&path); result = (*(dev->UNLINK)) (path); __TI_data_synch_INV(&_device, sizeof(_device)); __TI_resource_unlock(__TI_LOCK_DEVICE_TBL); return result; }
__bool uncaught_exception() THROW_NOTHING() /* Return TRUE if an exception is in the process of being thrown. */ { an_eh_stack_entry_ptr ehsep; __bool result; /* This function is used instead of simply using __curr_eh_stack_entry because of a problem using this variable in code that also uses it via generated EH code. */ ehsep = __get_curr_eh_stack_entry(); /*** START TI ADD ***/ __TI_resource_lock(__TI_LOCK_ATEXIT); /*** END TI ADD ***/ /* TRUE should be returned if uncaught_exception() is called after terminate() has been called by the implementation. */ result = terminate_called_by_runtime; /*** START TI ADD ***/ __TI_data_synch_WBINV(&terminate_called_by_runtime, sizeof(terminate_called_by_runtime)); __TI_resource_unlock(__TI_LOCK_ATEXIT); /*** END TI ADD ***/ for (; result == FALSE && ehsep != NULL; ehsep = ehsep->next) { if (ehsep->kind == ehsek_throw_processing_marker) { /* We are processing a throw. An exception cannot be thrown here without resulting in a call to terminate(). Note that this is TRUE even if a try block is nested inside the throw processing marker. */ result = TRUE; } /* if */ } /* for */ return result; } /* uncaught_exception */
_CODE_ACCESS int HOSTopen(const char *path, unsigned flags, int llv_fd) { int dev_fd; /*-----------------------------------------------------------------------*/ /* CRITICAL REGION TO PROTECT ACCESSES TO parmbuf[] AND _CIOBUF_ (see */ /* file header comment above for more about mutexes and data coherency). */ /*-----------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_HOST_CIO); LOADSHORT(parmbuf,llv_fd,0); LOADSHORT(parmbuf,flags,2); __TI_writemsg(_DTOPEN,parmbuf,(char *)path,strlen(path)+1); /* SEND NULL ACROSS ALSO */ __TI_readmsg(parmbuf,NULL); dev_fd = UNLOADSHORT(parmbuf,0); __TI_data_synch_WBINV(&parmbuf, sizeof(parmbuf)); __TI_resource_unlock(__TI_LOCK_HOST_CIO); return (dev_fd < 0) ? dev_fd : llv_fd; }
_CODE_ACCESS off_t HOSTlseek(int dev_fd, off_t offset, int origin) { off_t result; /*-----------------------------------------------------------------------*/ /* CRITICAL REGION TO PROTECT ACCESSES TO parmbuf[] AND _CIOBUF_ (see */ /* file header comment above for more about mutexes and data coherency). */ /*-----------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_HOST_CIO); LOADSHORT(parmbuf,dev_fd,0); LOAD32(parmbuf,offset,2); LOADSHORT(parmbuf,origin,6); __TI_writemsg(_DTLSEEK,parmbuf,NULL,0); __TI_readmsg(parmbuf,NULL); result = UNLOAD32(parmbuf,0); __TI_data_synch_WBINV(&parmbuf, sizeof(parmbuf)); __TI_resource_unlock(__TI_LOCK_HOST_CIO); return result; }
_CODE_ACCESS int add_device(char *name, unsigned flags, int (*dopen) (const char *path, unsigned flags, int llv_fd), int (*dclose) (int dev_fd), int (*dread) (int dev_fd, char *buf, unsigned count), int (*dwrite) (int dev_fd, const char *buf, unsigned count), off_t (*dlseek) (int dev_fd, off_t offset, int origin), int (*dunlink)(const char *path), int (*drename)(const char *old_name, const char *new_name)) { static _DATA_ACCESS int device_init = 0; _DEVICE *dt; /*-------------------------------------------------------------------------*/ /* CRITICAL REGION PROTECTS ACCESS TO _device[] */ /*-------------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_DEVICE_TBL); /*-------------------------------------------------------------------------*/ /* INITIALIZE DEVICE TABLE FIRST TIME AROUND */ /*-------------------------------------------------------------------------*/ if (!device_init) { for (device_init = 1, dt = &_device[1]; dt != &_device[_NDEVICE]; *(dt++)->name = '\0'); __TI_data_synch_WBINV(&device_init, sizeof(device_init)); } /*-------------------------------------------------------------------------*/ /* IF DEVICE WITH SPECIFIED 'name' ALREADY EXISTS IN _device[], THEN WE */ /* CAN'T ADD A NEW ONE WITH THE SAME NAME (note that the function pointers */ /* associated with the existing device are not updated). */ /*-------------------------------------------------------------------------*/ if (finddevice(name)) { __TI_data_synch_INV(&_device, sizeof(_device)); __TI_resource_unlock(__TI_LOCK_DEVICE_TBL); return 1; } /*-------------------------------------------------------------------------*/ /* SEARCH THE DEVICE TABLE FOR AN EMPTY SLOT, RETURN -1 IF NONE FOUND */ /*-------------------------------------------------------------------------*/ for (dt = &_device[1]; dt != _device+_NDEVICE && dt->name[0] != '\0'; ++dt); if (dt == &_device[_NDEVICE]) { __TI_data_synch_INV(&_device, sizeof(_device)); __TI_resource_unlock(__TI_LOCK_DEVICE_TBL); return -1; } strncpy(dt->name,name,8); dt->name[8] = '\0'; dt->flags = flags; dt->OPEN = dopen; dt->CLOSE = dclose; dt->READ = dread; dt->WRITE = dwrite; dt->LSEEK = dlseek; dt->UNLINK = dunlink; dt->RENAME = drename; __TI_data_synch_WBINV(&_device, sizeof(_device)); __TI_resource_unlock(__TI_LOCK_DEVICE_TBL); return 0; }
_CODE_ACCESS int open(const char *path, unsigned flags, int mode) { static _DATA_ACCESS int stream_init = 0; struct stream_info *ptr; _DEVICE *dev; int dev_fd; int llv_fd; /*-------------------------------------------------------------------------*/ /* CRITICAL REGION PROTECTS ACCESS TO _stream[] (see file header comment). */ /*-------------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_STREAM_TBL); /*-------------------------------------------------------------------------*/ /* INITIALIZE STREAM TABLE FIRST TIME AROUND */ /*-------------------------------------------------------------------------*/ if (!stream_init) { for (stream_init = 1, ptr = &_stream[3]; ptr != &_stream[_NSTREAM]; (ptr++)->dev = NULL); __TI_data_synch_WBINV(&stream_init, sizeof(stream_init)); } /*-------------------------------------------------------------------------*/ /* GET THE NEXT AVAILABLE FILE DESCRIPTOR - RETURN -1 IF NONE AVAILABLE */ /*-------------------------------------------------------------------------*/ for (ptr = &_stream[3]; ptr != &_stream[_NSTREAM] && ptr->dev; ++ptr); if (ptr == &_stream[_NSTREAM]) { __TI_data_synch_INV(&_stream, sizeof(_stream)); __TI_resource_unlock(__TI_LOCK_STREAM_TBL); return -1; } llv_fd = ptr - &_stream[0]; /*------------------------------------------------------------------------*/ /* GET DEVICE AND PEFORM OPEN - SET STREAM TABLE ENTRY AND FLAGS */ /*------------------------------------------------------------------------*/ /* CRITICAL REGION PROTECTS _device[] ACCESS THAT OCCURS IN getdevice() */ /* (see file header comment for more on mutex and data coherence). */ /*------------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_DEVICE_TBL); dev = getdevice(&path); dev_fd = (dev->flags & _BUSY) ? -1 : (*(dev->OPEN))(path,flags,llv_fd); if (dev_fd < 0) { __TI_data_synch_INV(&_stream, sizeof(_stream)); __TI_data_synch_INV(&_device, sizeof(_device)); __TI_resource_unlock(__TI_LOCK_DEVICE_TBL); __TI_resource_unlock(__TI_LOCK_STREAM_TBL); return dev_fd; } _stream[llv_fd].dev = dev; _stream[llv_fd].dfd = dev_fd; if (!(dev->flags & _MSA)) dev->flags |= _BUSY; __TI_data_synch_WBINV(&_stream, sizeof(_stream)); __TI_data_synch_WBINV(&_device, sizeof(_device)); __TI_resource_unlock(__TI_LOCK_DEVICE_TBL); __TI_resource_unlock(__TI_LOCK_STREAM_TBL); return llv_fd; }
_CODE_ACCESS int setvbuf(register FILE *_fp, register char *_buf, register int _type, register size_t _size) { /*------------------------------------------------------------------------*/ /* The current thread in a multi-threaded application must protect access */ /* to the file stream. In this case, _fp may be updated, so we must */ /* ensure that the local copy of _fp is flushed to shared memory before */ /* leaving the critical section (invalidated if it is not modified). */ /*------------------------------------------------------------------------*/ __TI_file_lock(_fp); /*------------------------------------------------------------------------*/ /* If the current stream is not associated with a file, return an error. */ /*------------------------------------------------------------------------*/ if (_fp->fd == -1 || (_type != _IONBF && _size <= 0)) { __TI_data_synch_INV(_fp, sizeof(FILE)); __TI_file_unlock(_fp); return (EOF); } /*------------------------------------------------------------------------*/ /* If a buffer already exists, free it if it was malloc'd, and reset all */ /* of the stream's buffer pointers. */ /*------------------------------------------------------------------------*/ if (_fp->buf) { if(_STCHK(_fp, _BUFFALOC)) free((_fp->buf)-1); _UNSET(_fp, _BUFFALOC); _fp->buf = NULL; _fp->pos = NULL; _fp->bufend = NULL; _fp->buff_stop = NULL; } /*------------------------------------------------------------------------*/ /* If NULL was used for the buffering mode, default to fully-buffered. */ /*------------------------------------------------------------------------*/ if (!_type) _type = _IOFBF; /*------------------------------------------------------------------------*/ /* Clear any previous buffering flags, and set the new one. */ /*------------------------------------------------------------------------*/ _UNSET(_fp, (_IOLBF | _IOFBF | _IONBF)); _SET(_fp, _type); /*------------------------------------------------------------------------*/ /* If a buffer was provided, but its size is only one byte, allocate a */ /* different one. Also, do not allow a buffer size greater than BUFSIZ. */ /* The buffer will always have one space at the beginning that is */ /* for UNGETC, in the event that an UNGETC is performed on an empty file, */ /* or when the buffer is full, but unread. */ /*------------------------------------------------------------------------*/ if (_size == 1) _buf = NULL; if (_size > BUFSIZ) _size = BUFSIZ; if (_buf) _fp->buf = (unsigned char*)_buf+1; else { /*---------------------------------------------------------------------*/ /* If allocating a buffer, provide _size bytes of usable space by */ /* incrementing _size, unless it is greater than BUFSIZ. */ /*---------------------------------------------------------------------*/ if (_size <= BUFSIZ) _size++; if (! (_fp->buf = (unsigned char*)malloc(_size))) { _SET(_fp, _STATERR); __TI_data_synch_WBINV(_fp, sizeof(FILE)); __TI_file_unlock(_fp); return (EOF); } _fp->buf++; _SET(_fp, _BUFFALOC); } _fp->pos = _fp->buff_stop = _fp->buf; _fp->bufend = _fp->buf + _size -1; __TI_data_synch_WBINV(_fp, sizeof(FILE)); __TI_file_unlock(_fp); /*------------------------------------------------------------------------*/ /* SETUP _CLEANUP_PTR SO ALL BUFFERS WILL BE FLUSHED AT EXIT. */ /*------------------------------------------------------------------------*/ /* __TI_cleanup_ptr is also a shared resource in multi-threaded */ /* applications, so accesses to it are also protected by the */ /* __TI_LOCK_FILE_TBL mutex. The current thread will also invalidate any */ /* local copy of __TI_cleanup_ptr in the data cache of the core that it */ /* is running on before leaving the critical section. */ /*------------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_FILE_TBL); __TI_cleanup_ptr = __TI_cleanup; __TI_data_synch_WBINV(&__TI_cleanup_ptr, sizeof(__TI_cleanup_ptr)); __TI_resource_unlock(__TI_LOCK_FILE_TBL); return (0); }
_CODE_ACCESS int fgetc(register FILE *_fp) { int retval = EOF; /*------------------------------------------------------------------------*/ /* The current thread in a multi-threaded application must protect access */ /* to __TI_LOCK_FILE_TBL shared resources (_ftable[], _ft_end, and */ /* _tmpnams[]). In this case, _ftable[] may be updated, so we must ensure */ /* that the local copy of _ftable[] is flushed to shared memory before */ /* leaving the critical section (invalidated if it is not modified). */ /*------------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_FILE_TBL); /*------------------------------------------------------------------------*/ /* Make sure that it is OK to read from this stream. */ /*------------------------------------------------------------------------*/ if (!_rd_ok(_fp)) goto fgetc_exit; /*------------------------------------------------------------------------*/ /* For non-buffered streams, call the lowlevel READ function. */ /*------------------------------------------------------------------------*/ if (_BUFFMODE(_fp) == _IONBF) { int errchk; char result; if (_STCHK(_fp, _UNGETC)) { _UNSET(_fp, _UNGETC); retval = (int)*(_fp->pos++); goto fgetc_exit; } errchk = read(_fp->fd, &result, 1); if (errchk <= 0) { _SET(_fp, (errchk == 0) ? _STATEOF : _STATERR); goto fgetc_exit; } retval = (int)result; goto fgetc_exit; } /*------------------------------------------------------------------------*/ /* If the buffer has been entirely read, or is empty, call _BUFF_READ to */ /* fill the buffer. */ /*------------------------------------------------------------------------*/ if (_fp->pos == _fp->buff_stop) _buff_read(_fp); /*------------------------------------------------------------------------*/ /* If the buffer read was unsuccessful, return an EOF. Otherwise, clear */ /* the _UNGETC flag in the stream, and return the next character. */ /*------------------------------------------------------------------------*/ if (_STCHK(_fp, (_STATERR | _STATEOF))) goto fgetc_exit; _UNSET(_fp, _UNGETC); retval = *(_fp->pos++); fgetc_exit: __TI_data_synch_WBINV(&_ftable, sizeof(_ftable)); __TI_resource_unlock(__TI_LOCK_FILE_TBL); return (retval); }
_CODE_ACCESS size_t fread(void *_ptr, size_t _size, size_t _count, FILE *_fp) { /*------------------------------------------------------------------------*/ /* Local variables */ /*------------------------------------------------------------------------*/ unsigned char *fpos = (unsigned char *)_ptr; size_t num_left = _size * _count, num_read = 0, num_to_read = 0; /*------------------------------------------------------------------------*/ /* The current thread in a multi-threaded application must protect access */ /* to __TI_LOCK_FILE_TBL shared resources (_ftable[], _ft_end, and */ /* _tmpnams[]). In this case, _ftable[] may be updated, so we must ensure */ /* that the local copy of _ftable[] is flushed to shared memory before */ /* leaving the critical section (invalidated if it is not modified). */ /*------------------------------------------------------------------------*/ __TI_resource_lock(__TI_LOCK_FILE_TBL); /*------------------------------------------------------------------------*/ /* Make sure that the file is readable. */ /*------------------------------------------------------------------------*/ if (!_rd_ok(_fp) || _size == 0 || _count == 0) { __TI_data_synch_INV(&_ftable, sizeof(_ftable)); __TI_resource_unlock(__TI_LOCK_FILE_TBL); return (0); } /*------------------------------------------------------------------------*/ /* If the stream is non-buffered, call the lowlevel READ function. */ /*------------------------------------------------------------------------*/ if (_BUFFMODE(_fp) == _IONBF) { int num_read = 0; while (num_left > 0) { int read_return; if (_STCHK(_fp, _UNGETC)) { *fpos = *(_fp->pos++); _UNSET(_fp, _UNGETC); read_return = 1; } else read_return = (size_t)(read(_fp->fd, (char *)fpos + num_read, num_left)); if (read_return < 0) { _SET(_fp, _STATERR); break; } else if (read_return == 0) { _SET(_fp, _STATEOF); break; } else { num_read += read_return; num_left -= read_return; } } __TI_data_synch_WBINV(&_ftable, sizeof(_ftable)); __TI_resource_unlock(__TI_LOCK_FILE_TBL); return (num_read / _size); } while (num_left > 0) { /*---------------------------------------------------------------------*/ /* If the buffer has been completely read, fill it up. Exit the loop */ /* if an I/O error occurs, or the end of the file is reached. */ /*---------------------------------------------------------------------*/ if(_fp->pos == _fp->buff_stop) _buff_read(_fp); if(_STCHK(_fp, (_STATERR | _STATEOF))) break; /*---------------------------------------------------------------------*/ /* Determine how many characters can fit in the buffer, and read them */ /* in. */ /*---------------------------------------------------------------------*/ num_to_read = (num_left < (_fp->buff_stop - _fp->pos)) ? num_left : (_fp->buff_stop - _fp->pos); memcpy(fpos, _fp->pos, num_to_read); /*---------------------------------------------------------------------*/ /* Update pointers and counters. */ /*---------------------------------------------------------------------*/ fpos += num_to_read; _fp->pos += num_to_read; num_read += num_to_read; num_left -= num_to_read; } /*------------------------------------------------------------------------*/ /* Clear the _UNGETC flag in the stream, and return the number of blocks */ /* read. */ /*------------------------------------------------------------------------*/ _UNSET(_fp, _UNGETC); __TI_data_synch_WBINV(&_ftable, sizeof(_ftable)); __TI_resource_unlock(__TI_LOCK_FILE_TBL); return (num_read / _size); }