| @c -*- Texinfo -*- |
| @node Syscalls |
| @chapter System Calls |
| |
| @cindex linking the C library |
| The C subroutine library depends on a handful of subroutine calls for |
| operating system services. If you use the C library on a system that |
| complies with the POSIX.1 standard (also known as IEEE 1003.1), most of |
| these subroutines are supplied with your operating system. |
| |
| If some of these subroutines are not provided with your system---in |
| the extreme case, if you are developing software for a ``bare board'' |
| system, without an OS---you will at least need to provide do-nothing |
| stubs (or subroutines with minimal functionality) to allow your |
| programs to link with the subroutines in @code{libc.a}. |
| |
| @menu |
| * Stubs:: Definitions for OS interface |
| * Reentrant Syscalls:: Reentrant covers for OS subroutines |
| @end menu |
| |
| @node Stubs |
| @section Definitions for OS interface |
| @cindex stubs |
| |
| @cindex subroutines for OS interface |
| @cindex OS interface subroutines |
| This is the complete set of system definitions (primarily subroutines) |
| required; the examples shown implement the minimal functionality |
| required to allow @code{libc} to link, and fail gracefully where OS |
| services are not available. |
| |
| Graceful failure is permitted by returning an error code. A minor |
| complication arises here: the C library must be compatible with |
| development environments that supply fully functional versions of these |
| subroutines. Such environments usually return error codes in a global |
| @code{errno}. However, the Red Hat newlib C library provides a @emph{macro} |
| definition for @code{errno} in the header file @file{errno.h}, as part |
| of its support for reentrant routines (@pxref{Reentrancy,,Reentrancy}). |
| |
| @cindex @code{errno} global vs macro |
| The bridge between these two interpretations of @code{errno} is |
| straightforward: the C library routines with OS interface calls |
| capture the @code{errno} values returned globally, and record them in |
| the appropriate field of the reentrancy structure (so that you can query |
| them using the @code{errno} macro from @file{errno.h}). |
| |
| This mechanism becomes visible when you write stub routines for OS |
| interfaces. You must include @file{errno.h}, then disable the macro, |
| like this: |
| |
| @example |
| #include <errno.h> |
| #undef errno |
| extern int errno; |
| @end example |
| |
| @noindent |
| The examples in this chapter include this treatment of @code{errno}. |
| |
| @ftable @code |
| @item _exit |
| Exit a program without cleaning up files. If your system doesn't |
| provide this, it is best to avoid linking with subroutines that require |
| it (@code{exit}, @code{system}). |
| |
| @item close |
| Close a file. Minimal implementation: |
| |
| @example |
| int close(int file) @{ |
| return -1; |
| @} |
| @end example |
| |
| @item environ |
| A pointer to a list of environment variables and their values. For a |
| minimal environment, this empty list is adequate: |
| |
| @example |
| char *__env[1] = @{ 0 @}; |
| char **environ = __env; |
| @end example |
| |
| @item execve |
| Transfer control to a new process. Minimal implementation (for a system |
| without processes): |
| |
| @example |
| #include <errno.h> |
| #undef errno |
| extern int errno; |
| int execve(char *name, char **argv, char **env) @{ |
| errno = ENOMEM; |
| return -1; |
| @} |
| @end example |
| |
| @item fork |
| Create a new process. Minimal implementation (for a system without processes): |
| |
| @example |
| #include <errno.h> |
| #undef errno |
| extern int errno; |
| int fork(void) @{ |
| errno = EAGAIN; |
| return -1; |
| @} |
| @end example |
| |
| @item fstat |
| Status of an open file. For consistency with other minimal |
| implementations in these examples, all files are regarded as character |
| special devices. The @file{sys/stat.h} header file required is |
| distributed in the @file{include} subdirectory for this C library. |
| |
| @example |
| #include <sys/stat.h> |
| int fstat(int file, struct stat *st) @{ |
| st->st_mode = S_IFCHR; |
| return 0; |
| @} |
| @end example |
| |
| @item getpid |
| Process-ID; this is sometimes used to generate strings unlikely to |
| conflict with other processes. Minimal implementation, for a system |
| without processes: |
| |
| @example |
| int getpid(void) @{ |
| return 1; |
| @} |
| @end example |
| |
| @item isatty |
| Query whether output stream is a terminal. For consistency with the |
| other minimal implementations, which only support output to |
| @code{stdout}, this minimal implementation is suggested: |
| |
| @example |
| int isatty(int file) @{ |
| return 1; |
| @} |
| @end example |
| |
| @item kill |
| Send a signal. Minimal implementation: |
| |
| @example |
| #include <errno.h> |
| #undef errno |
| extern int errno; |
| int kill(int pid, int sig) @{ |
| errno = EINVAL; |
| return -1; |
| @} |
| @end example |
| |
| @item link |
| Establish a new name for an existing file. Minimal implementation: |
| |
| @example |
| #include <errno.h> |
| #undef errno |
| extern int errno; |
| int link(char *old, char *new) @{ |
| errno = EMLINK; |
| return -1; |
| @} |
| @end example |
| |
| @item lseek |
| Set position in a file. Minimal implementation: |
| |
| @example |
| int lseek(int file, int ptr, int dir) @{ |
| return 0; |
| @} |
| @end example |
| |
| @item open |
| Open a file. Minimal implementation: |
| |
| @example |
| int open(const char *name, int flags, int mode) @{ |
| return -1; |
| @} |
| @end example |
| |
| @item read |
| Read from a file. Minimal implementation: |
| |
| @example |
| int read(int file, char *ptr, int len) @{ |
| return 0; |
| @} |
| @end example |
| |
| @item sbrk |
| Increase program data space. As @code{malloc} and related functions |
| depend on this, it is useful to have a working implementation. The |
| following suffices for a standalone system; it exploits the symbol |
| @code{_end} automatically defined by the GNU linker. |
| |
| @example |
| @group |
| caddr_t sbrk(int incr) @{ |
| extern char _end; /* @r{Defined by the linker} */ |
| static char *heap_end; |
| char *prev_heap_end; |
| |
| if (heap_end == 0) @{ |
| heap_end = &_end; |
| @} |
| prev_heap_end = heap_end; |
| if (heap_end + incr > stack_ptr) @{ |
| write (1, "Heap and stack collision\n", 25); |
| abort (); |
| @} |
| |
| heap_end += incr; |
| return (caddr_t) prev_heap_end; |
| @} |
| @end group |
| @end example |
| |
| @item stat |
| Status of a file (by name). Minimal implementation: |
| |
| @example |
| int stat(char *file, struct stat *st) @{ |
| st->st_mode = S_IFCHR; |
| return 0; |
| @} |
| @end example |
| |
| @item times |
| Timing information for current process. Minimal implementation: |
| |
| @example |
| int times(struct tms *buf) @{ |
| return -1; |
| @} |
| @end example |
| |
| @item unlink |
| Remove a file's directory entry. Minimal implementation: |
| |
| @example |
| #include <errno.h> |
| #undef errno |
| extern int errno; |
| int unlink(char *name) @{ |
| errno = ENOENT; |
| return -1; |
| @} |
| @end example |
| |
| @item wait |
| Wait for a child process. Minimal implementation: |
| @example |
| #include <errno.h> |
| #undef errno |
| extern int errno; |
| int wait(int *status) @{ |
| errno = ECHILD; |
| return -1; |
| @} |
| @end example |
| |
| @item write |
| Write to a file. @file{libc} subroutines will use this |
| system routine for output to all files, @emph{including} |
| @code{stdout}---so if you need to generate any output, for example to a |
| serial port for debugging, you should make your minimal @code{write} |
| capable of doing this. The following minimal implementation is an |
| incomplete example; it relies on a @code{outbyte} subroutine (not |
| shown; typically, you must write this in assembler from examples |
| provided by your hardware manufacturer) to actually perform the output. |
| |
| @example |
| @group |
| int write(int file, char *ptr, int len) @{ |
| int todo; |
| |
| for (todo = 0; todo < len; todo++) @{ |
| outbyte (*ptr++); |
| @} |
| return len; |
| @} |
| @end group |
| @end example |
| |
| @end ftable |
| |
| @page |
| @node Reentrant Syscalls |
| @section Reentrant covers for OS subroutines |
| |
| Since the system subroutines are used by other library routines that |
| require reentrancy, @file{libc.a} provides cover routines (for example, |
| the reentrant version of @code{fork} is @code{_fork_r}). These cover |
| routines are consistent with the other reentrant subroutines in this |
| library, and achieve reentrancy by using a reserved global data block |
| (@pxref{Reentrancy,,Reentrancy}). |
| |
| @c FIXME!!! The following ignored text specifies how this section ought |
| @c to work; however, both standalone info and Emacs info mode fail when |
| @c confronted with nodes beginning `_' as of 24may93. Restore when Info |
| @c readers fixed! |
| @ignore |
| @menu |
| * _open_r:: Reentrant version of open |
| * _close_r:: Reentrant version of close |
| * _lseek_r:: Reentrant version of lseek |
| * _read_r:: Reentrant version of read |
| * _write_r:: Reentrant version of write |
| * _link_r:: Reentrant version of link |
| * _unlink_r:: Reentrant version of unlink |
| * _stat_r:: Reentrant version of stat |
| * _fstat_r:: Reentrant version of fstat |
| * _sbrk_r:: Reentrant version of sbrk |
| * _fork_r:: Reentrant version of fork |
| * _wait_r:: Reentrant version of wait |
| @end menu |
| |
| @down |
| @include reent/filer.def |
| @include reent/execr.def |
| @include reent/statr.def |
| @include reent/fstatr.def |
| @include reent/linkr.def |
| @include reent/unlinkr.def |
| @include reent/sbrkr.def |
| @up |
| @end ignore |
| |
| @ftable @code |
| @item _open_r |
| A reentrant version of @code{open}. It takes a pointer |
| to the global data block, which holds @code{errno}. |
| |
| @example |
| int _open_r(void *@var{reent}, |
| const char *@var{file}, int @var{flags}, int @var{mode}); |
| @end example |
| |
| @ifset STDIO64 |
| @item _open64_r |
| A reentrant version of @code{open64}. It takes a pointer |
| to the global data block, which holds @code{errno}. |
| |
| @example |
| int _open64_r(void *@var{reent}, |
| const char *@var{file}, int @var{flags}, int @var{mode}); |
| @end example |
| @end ifset |
| |
| @item _close_r |
| A reentrant version of @code{close}. It takes a pointer to the global |
| data block, which holds @code{errno}. |
| |
| @example |
| int _close_r(void *@var{reent}, int @var{fd}); |
| @end example |
| |
| @item _lseek_r |
| A reentrant version of @code{lseek}. It takes a pointer to the global |
| data block, which holds @code{errno}. |
| |
| @example |
| off_t _lseek_r(void *@var{reent}, |
| int @var{fd}, off_t @var{pos}, int @var{whence}); |
| @end example |
| |
| @ifset STDIO64 |
| @item _lseek64_r |
| A reentrant version of @code{lseek64}. It takes a pointer to the global |
| data block, which holds @code{errno}. |
| |
| @example |
| off_t _lseek64_r(void *@var{reent}, |
| int @var{fd}, off_t @var{pos}, int @var{whence}); |
| @end example |
| @end ifset |
| |
| @item _read_r |
| A reentrant version of @code{read}. It takes a pointer to the global |
| data block, which holds @code{errno}. |
| |
| @example |
| long _read_r(void *@var{reent}, |
| int @var{fd}, void *@var{buf}, size_t @var{cnt}); |
| @end example |
| |
| @item _write_r |
| A reentrant version of @code{write}. It takes a pointer to the global |
| data block, which holds @code{errno}. |
| |
| @example |
| long _write_r(void *@var{reent}, |
| int @var{fd}, const void *@var{buf}, size_t @var{cnt}); |
| @end example |
| |
| @item _fork_r |
| A reentrant version of @code{fork}. It takes a pointer to the global |
| data block, which holds @code{errno}. |
| |
| @example |
| int _fork_r(void *@var{reent}); |
| @end example |
| |
| @item _wait_r |
| A reentrant version of @code{wait}. It takes a pointer to the global |
| data block, which holds @code{errno}. |
| |
| @example |
| int _wait_r(void *@var{reent}, int *@var{status}); |
| @end example |
| |
| @item _stat_r |
| A reentrant version of @code{stat}. It takes a pointer to the global |
| data block, which holds @code{errno}. |
| |
| @example |
| int _stat_r(void *@var{reent}, |
| const char *@var{file}, struct stat *@var{pstat}); |
| @end example |
| |
| @item _fstat_r |
| A reentrant version of @code{fstat}. It takes a pointer to the global |
| data block, which holds @code{errno}. |
| |
| @example |
| int _fstat_r(void *@var{reent}, |
| int @var{fd}, struct stat *@var{pstat}); |
| @end example |
| |
| @ifset STDIO64 |
| @item _fstat64_r |
| A reentrant version of @code{fstat64}. It takes a pointer to the global |
| data block, which holds @code{errno}. |
| |
| @example |
| int _fstat64_r(void *@var{reent}, |
| int @var{fd}, struct stat *@var{pstat}); |
| @end example |
| @end ifset |
| |
| @item _link_r |
| A reentrant version of @code{link}. It takes a pointer to the global |
| data block, which holds @code{errno}. |
| |
| @example |
| int _link_r(void *@var{reent}, |
| const char *@var{old}, const char *@var{new}); |
| @end example |
| |
| @item _unlink_r |
| A reentrant version of @code{unlink}. It takes a pointer to the global |
| data block, which holds @code{errno}. |
| |
| @example |
| int _unlink_r(void *@var{reent}, const char *@var{file}); |
| @end example |
| |
| @item _sbrk_r |
| A reentrant version of @code{sbrk}. It takes a pointer to the global |
| data block, which holds @code{errno}. |
| |
| @example |
| char *_sbrk_r(void *@var{reent}, size_t @var{incr}); |
| @end example |
| @end ftable |