Chapter 14
Minimal C Library: liboskit_c.a

14.1 Introduction

The OSKit’s minimal C library is a subset of a standard ANSI/POSIX C library designed specifically for use in kernels or other restricted environments in which a “full-blown” C library cannot be used. The minimal C library provides many simple standard functions such as string, memory, and formatted output functions: functions that are often useful in kernels as well as application programs, but because ordinary application-oriented C libraries are unusable in kernels, must usually be reimplemented or manually “pasted” into the kernel sources with appropriate modifications to make them usable in the kernel environment. The versions of these functions provided by the OSKit minimal C library, like the other components of the OSKit, are designed to be as generic and context-independent as possible, so that they can be used in arbitrary environments without the developer having to resort to the traditional manual cut-and-paste methods. This cleaner strategy brings with it the well-known advantages of careful code reuse: the kernel itself becomes smaller and simpler due to fewer extraneous “utility” functions hanging around in the sources; it is easier to maintain both the kernel, for the above reason, and the standard utility functions it uses, because there is only one copy of each to maintain; finally, the kernel can easily adopt new, improved implementations of common performance-critical functions as they become available, simply by linking against a new version of the minimal C library (e.g., new versions of memcpy or bzero optimized for particular architectures or newer family members of a given architecture).

In general, the minimal C library provides only functions specified in the ANSI C or POSIX.1 standards, and only a subset thereof. Furthermore, the provided implementations of these functions are designed to be as independent as possible from each other and from the environment in which they run, allowing arbitrary subsets of these functions to be used when needed without pulling in any more functionality than necessary and without requiring the OS developer to provide significant support infrastructure. For example, all of the “simple” functions which merely perform some computation on or manipulation of supplied data, such as the string instructions, are guaranteed to be completely independent of each other.

The functions that are inherently environment-dependent in some way, such as printf, which assumes the existence of some kind of “standard output” or “console,” are implemented in terms of other clearly specified, environment-dependent functions. Thus, in order to use the minimal C library’s implementation of printf, the OS developer must provide appropriate console_putchar and console_putbytes routines to be used to write characters to whatever acts as the “standard output” in the current environment. All such dependencies between C library functions are explicitly stated in this document, so that it is always clear what additional functions the developer must supply in order to make use of a set of functions provided by the minimal C library.

Since almost all of the functions and definitions provided by the OSKit minimal C library implement well-known, well-defined ANSI and POSIX C library interfaces which are amply documented elsewhere, we do not attempt to describe the purpose and behavior of each function in this chapter. Instead, only the peculiarities relevant to the minimal C library, such as implementation interdependencies and side effects, are described here.

Note that many files and functions in the minimal C library are derived or taken directly from other source code bases, particularly Mach and BSD. Specific attributions are made in the source files themselves.

14.2 POSIX Interface

Some of the functions provided in the minimal C library depend on lower level I/O routines in the POSIX library (see Section 20) to provide mappings to the appropriate OSKit COM interfaces. For example, fopen in the C library will chain to open in the POSIX library, which in turn will chain to the appropriate oskit_dir and oskit_file COM operations.

14.3 Unsupported Features

The following features in many C libraries are deliberately unsupported by the minimal C library, for reasons described below, and will remain unsupported unless a compelling counterargument arises:

14.4 Header Files

When the OSKit is installed using make install, a set of standard ANSI/POSIX-defined header files, containing definitions and function prototypes for the minimal C library, are installed in the selected include directory under the subdirectory oskit/c/. For example, the version of the ANSI C header file string.h provided with the minimal C library is installed as prefix /include/oskit/c/string.h. These header files are installed in a subdirectory rather than in the top level include directory so that if the OSKit is installed in a standard place shared by other packages and/or system files, such as /usr or /usr/local, the minimal C library’s header files will not conflict with header files provided by normal application-oriented C libraries, nor will applications “accidentally” use the minimal C library’s header files when they really want the normal C library’s header files.

There are two main ways a kernel or other program can explicitly use the OSKit minimal C library’s header files. The first is by including the oskit/c/ prefix directly in all relevant #include statements; e.g., ‘#include <oskit/c/string.h>’ instead of ‘#include <string.h>’. However, since this method effectively makes the client code somewhat specific to the OSKit minimal C library by hard-coding OSKit-specific pathnames into the #include statements, this method should generally only be used if for some reason the code in question is extremely dependent on the OSKit minimal C library in particular, and it would never make sense for it to include corresponding header files from a different C library.

For typical code using the minimal C library, which simply needs “a printf” or “a strcpy,” the preferred method of including the library’s header files is to code the #include lines without the oskit/c/ prefix, just as in application code using an ordinary C library, and then add an appropriate -I (include directory) directive to the compiler command line so that the oskit/c/ directory will be scanned automatically for these header files before the top-level include directory and other include directories in the system are searched. Typically this -I directive can be added to the CFLAGS variable in the Makefile used to build the program in question. In fact, the OSKit itself uses this method to allow code in other toolkit components and in the minimal C library itself to make use of definitions and functions provided by the minimal C library. (Of course, these dependencies are clearly documented, so that if you want to use other OSKit components but not the minimal C library, or only part of the minimal C library, it is possible to do so cleanly.)

Except when otherwise noted, all of the definitions and functions described in this section are very simple, have few dependencies, and behave as in ordinary C libraries. Functions that are not self-contained and interact with the surrounding environment in non-trivial ways (e.g., the memory allocation functions) are described in more detail in later sections.

14.4.1 a.out.h: semi-standard a.out file format definitions

DESCRIPTION

This header file simply cross-includes the header file oskit/exec/a.out.h, which is part of the executable interpreter library (see Section 35.1.2) and provides a minimal set of definitions describing a.out-format executable and object files. Although this header file is not standard ANSI or POSIX (thank goodness!), it is a fairly strong Unix tradition, and is especially relevant to operating system code, and therefore is provided as part of the OSKit.

14.4.2 alloca.h: explicit stack-based memory allocation

DESCRIPTION

This header file defines the alloca pseudo-function, which allows C code to dynamically allocate memory on the calling function’s stack frame, which will be freed automatically when the function returns. This header is not ANSI or POSIX but is a fairly well-established tradition. The implementation of this function currently depends on being compiled with gcc.

14.4.3 assert.h: program diagnostics facility

DESCRIPTION

This header file provides a standard assert macro as described in the C standard. All uses of the assert macro are compiled out (they generate no code) if the preprocessor symbol NDEBUG is defined before this header file is included.

14.4.4 ctype.h: character handling functions

DESCRIPTION

This header file provides implementations of the following standard character handling functions:

isascii:
Tests if a character is in the range 0-127. This is not supplied in ISO C but exists on many systems.
isalnum:
Tests if a character is alphanumeric.
isalpha:
Tests if a character is alphabetic.
iscntrl:
Tests if a character is a control character.
isdigit:
Tests if a character is a decimal digit.
isgraph:
Tests if a character is a printable non-space character.
islower:
Tests if a character is a lowercase letter.
isprint:
Tests if a character is a printable character, including space.
ispunct:
Tests if a character is a punctuation mark.
isspace:
Tests if a character is a whitespace character of any kind.
isupper:
Tests if a character is a uppercase letter.
isxdigit:
Tests if a character is a hexadecimal digit.
toascii:
Converts an integer into a 7-bit ASCII character.
tolower:
Converts a character to lowercase.
toupper:
Converts a character to uppercase.

The implementations of these functions provided by the minimal C library are directly-coded inline functions, and do not reference any global data structures such as character type arrays. They do not support locales (see Section 14.3), and only recognize the basic 7-bit ASCII character set (all characters above 126 are considered to be control characters).

14.4.5 errno.h: error numbers

DESCRIPTION

This file declares the global errno variable, and defines symbolic constants for all the errno values defined in the ISO/ANSI C, POSIX.1, and UNIX standards. They are provided mainly for the convenience of clients that can benefit from standardized error codes and do not already have their own error handling scheme and error code namespace. The symbols defined in this header file have the same values as the corresponding symbols defined in oskit/error.h (see 4.6.2), which are the error codes used through the OSKit’s COM interfaces; this way, error codes from arbitrary OSKit components can be used directly as errno values at least by programs that use the minimal C library.

The main disadvantage of using COM error codes as errno values is that, since they don’t start from around 0 like typical Unix errno values, it’s impossible to provide a traditional Unix-style sys_errlist table for them. However, they are fully compatible with the POSIX-blessed strerror and perror routines, and in any case the minimal C library is not intended to support “legacy” applications directly - for that purpose, a “real” C library would be more appropriate, and such a C library would probably use more traditional errno values, doing appropriate translation when interacting with COM interfaces.

14.4.6 fcntl.h: POSIX low-level file control

DESCRIPTION

This header file defines prototypes for the low-level POSIX functions creat and open, and provides symbolic constants for the POSIX open mode flags (O_*). Neither creat nor open are defined in the minimal C library, but instead are defined in the POSIX library (see Section 20).

The open mode constants defined by this header are identical to and interchangeable with the corresponding constants defined in oskit/fs/file.h for the oskit_file COM interface (see 9.4). These definitions are provided so that clients may standardize on a single set of defintions, which are the same as those used by the COM components. For example, the FreeBSD C library includes this header file, thus providing compatibility between the the two libraries and the disk-based file systems.

14.4.7 float.h: constants describing floating-point types

DESCRIPTION

This header file provides the standard set of symbols required by the ISO C standard describing various characteristics of the float, double, and long double types. There is nothing special about the OSKit’s definition of these symbols; see the ANSI/ISO C or Single UNIX standard for detailed information about this header file.

14.4.8 limits.h: architecture-specific limits

DESCRIPTION

This header file defines the following standard symbols describing architecture-specific limits of basic numeric types:

CHAR_BIT:
Number of bytes in a char.
CHAR_MAX:
Maximum value of a char.
CHAR_MIN:
Minimum value of a char.
SCHAR_MAX:
Maximum value of a signed char.
SCHAR_MIN:
Minimum value of a signed char.
UCHAR_MAX:
Maximum value of a unsigned char.
SHRT_MAX:
Maximum value of a short.
SHRT_MIN:
Minimum value of a short.
USHRT_MAX:
Maximum value of a unsigned short.
INT_MAX:
Maximum value of a int.
INT_MIN:
Minimum value of a int.
UINT_MAX:
Maximum value of a unsigned int.
LONG_MAX:
Maximum value of a long.
LONG_MIN:
Minimum value of a long.
ULONG_MAX:
Maximum value of a unsigned long.
SSIZE_MAX:
Maximum value of a size_t.

The minimal C library’s limits.h does not define any of the POSIX symbols describing operating system-specific limits, such as maximum number of open files, since the minimal C library has know way of knowing how it will be used and thus what these values should be.

14.4.9 malloc.h: memory allocator definitions

DESCRIPTION

This header file defines common types and functions used by the minimal C library’s default memory allocation functions. This header file is not a standard POSIX or X/Open CAE header file; instead its purpose is to expose the implementation of the malloc facility so that the client can fully control it and use it in arbitrary contexts.

The malloc package implements the following standard allocation routines (also defined in stdlib.h).

malloc:
Allocate a chunk of memory in the caller’s heap.
mustmalloc:
Like malloc, but calls panic if the allocation fails.
memalign:
Allocate a chunk of aligned memory.
calloc:
Allocate a zero-filled chunk of memory.
mustcalloc:
Like calloc, but calls panic if the allocation fails.
realloc:
Changes the allocated size of a chunk of memory while preserving the contents of that memory.
free:
Releases a chunk of memory.

The base C library also provides additional routines that allocate chunks of memory that are naturally aligned. The user must keep track of the size of each allocated chunk and free the memory with sfree rather than the ordinary free.

smalloc:
Allocate a chunk of user-managed memory in the caller’s heap.
smemalign:
Allocate an aligned chunk of user-managed memory.
scalloc:
Currently not implemented.
srealloc:
Currently not implemented.
sfree:
Free a user-managed chunk of memory previously allocated by an s* allocation.

The following are specific to the LMM implementation. They take an additional flag to allow requests for specific types of memory.

mallocf:
Allocate a chunk of user-managed memory in the caller’s heap.
memalignf:
Allocate an aligned chunk of user-managed memory.
smallocf:
Allocate a chunk of user-managed memory in the caller’s heap.
smemalignf:
Allocate an aligned chunk of user-managed memory.

The following functions are frequently overridden by the client OS:

morecore:
Called by malloc and realloc varients when an attempt to allocate memory from the LMM fails. The default version does nothing.
mem_lock:
Called to ensure exclusive access to the underlying LMM. The default version does nothing.
mem_unlock:
Called when exclusive access is no longer needed. The default version does nothing.

See Section 14.5 for details on these functions.

14.4.10 math.h: floating-point math functions and constants

DESCRIPTION

This header file provides function prototypes for the math functions conventionally found in libm, the standard C math library. Although these functions are not part of the minimal C library, an implementation of the math functions is available in the FreeBSD math library; see Chapter 22 for details. This header file also defines various floating-point constants, such as the value of p, as described in the Unix CAE specification. Since these functions and their implementations are fully standard, they are not described in further detail here; refer to the ISO C and Unix standards for more information.

14.4.11 netdb.h: definitions for network database operations

DESCRIPTION

This header file defines structures and prototypes for Internet domain name service (DNS) operations, such as finding the IP address for a host name and vice versa.

14.4.12 setjmp.h: nonlocal jumps

DESCRIPTION

This header provides definitions for the minimal setjmp/longjmp facility provided in the minimal C library. This facility differs from standard ones in two ways:

In summary, this header file defines the following symbols:

jmp_buf:
An array type describing a buffer for setjmp to save state in.
setjmp:
Function to record the current stack and register state.
longjmp:
Function to return to a previously saved state.

14.4.13 signal.h: signal handling

DESCRIPTION

The minimal C library has no support for signals, and thus does not implement any of the functions prototyped in this header file. The header file is here for client OSes that wish to support POSIX signal semantics.

14.4.14 stdarg.h: variable arguments

DESCRIPTION

This header provides definitions for accessing variable argument lists. It simply chains to x86-specific definitions.

va_list:
Type used to declare local state variable used in traversing the variable argument list.
va_start:
Initializes the va_list state variable. Must be called before va_arg or va_end.
va_arg:
This macro returns the value of the next argument in the variable argument list, and advances the va_list state variable.
va_end:
This macro is called after all the arguments have been read.

14.4.15 stddef.h: common definitions

DESCRIPTION

This header file defines the symbol NULL and the type size_t if they haven’t been defined already. It also defines wchar_t and the offsetof macro.

14.4.16 stdio.h: standard input/output

DESCRIPTION

This header provides definitions for the standard input and output facilities provided by the minimal C library. Many of these routines simply chain to the low-level I/O routines in the POSIX library, and do no buffering.

putchar:
Output a character to stdout.
puts:
Output a string to a stream.
printf:
Formatted output to stdout.
vprintf:
Formatted output to stdout with a stdarg.h va_list argument.
sprintf:
Formatted output to a string buffer.
snprintf:
Formatted output of up to len characters into a string buffer.
vsprintf:
Formatted output to a string buffer with a stdarg.h va_list argument.
vsnprintf:
Formatted output of up to len characters into a string buffer with a stdarg.h va_list argument.
getchar:
Input a character from stdin.
gets:
Input a string from stdin.
fgets:
Input a string from a stream.
fopen:
Open a stream.
fclose:
Close a stream.
fread:
Read bytes from a stream.
fwrite:
Write bytes to a stream.
fputc:
Output a character to a stream.
fputs:
Output a string to a stream.
fgetc:
Input a character from a stream.
fprintf:
Formatted output to a stream.
vfprintf:
Formatted output to a stream with a stdarg.h va_list argument.
fscanf:
Formatted input from a stream.
sscanf:
Formatted input from a string.
fseek:
Reposition a stream.
feof:
Check for end-of-file in an input stream.
ftell:
Return the current position in a stream.
rewind:
Reset a stream to the beginning.
hexdump:
Print a buffer in hexdump style.
putc:
Macro-expanded to fputc.

14.4.17 stdlib.h: standard library functions

DESCRIPTION

This header file defines the symbol NULL and the type size_t if they haven’t been defined already, and provides prototypes for the following functions in the minimal C library:

atol:
Convert an ASCII decimal number into a long.
strtol:
Convert an ASCII number into a long.
strtoul:
Convert an ASCII number into an unsigned long.
strtod:
Convert ASCII string to double.
malloc:
Allocate a chunk of memory in the caller’s heap.
mustmalloc:
Like malloc, but calls panic if the allocation fails.
calloc:
Allocate a zero-filled chunk of memory.
mustcalloc:
Like calloc, but calls panic if the allocation fails.
realloc:
Changes the allocated size of a chunk of memory while preserving the contents of that memory.
free:
Releases a chunk of memory.
exit:
Cause normal program termination; see Section 14.8.1.
abort:
Cause abnormal program termination; see Section 14.8.2.
panic:
Cause abnormal termination and print a message. Not a standard C function; see Section 14.8.3.
atexit:
Register a function to be called on exit.
getenv:
Search for a string in the environment.

Prototypes for the following functions are also provided, but they are not implemented in the minimal C library. See the FreeBSD C library in Section 21.

abs:
Compute the absolute value of an integer.
atoi:
Convert an ASCII decimal number into an int.
atof:
Convert ASCII string to double.
qsort:
Sort an array of objects.
rand:
Compute a pseudo-random integer. Not thread safe; uses static data.
srand:
Seed the pseudo-random number generator. Not thread safe; uses static data.

14.4.18 string.h: string handling functions

DESCRIPTION

This header file defines the symbol NULL if it hasn’t been defined already, and provides prototypes for the following functions in the minimal C library:

memcpy:
Copy data from one location in memory to another. Our implementation behaves correctly when source and destination overlap.
memmove:
Like memcpy but is guaranteed to behave correctly when source and destination overlap.
memset:
Set the contents of a block of memory to a uniform value.
strlen:
Find the length of a null-terminated string.
strcpy:
Copy a string to another location in memory.
strncpy:
Copy a string, up to a specified maximum length.
strdup:
Return a copy of a string in newly-allocated memory. Depends on malloc, Section 14.5.2.
strcat:
Concatenate a second string onto the end of a first.
strncat:
Concatenate two strings, up to a specified maximum length.
strcmp:
Compare two strings.
strncmp:
Compare two strings, up to a specified maximum length.
strchr:
Find the first occurrence of a character in a string.
strrchr:
Find the last occurrence of a character in a string.
strstr:
Find the first occurrence of a substring in a larger string.
strtok:
Scan for tokens in a string. Not thread safe; uses static data.
strpbrk:
Locate the first occurrence in a string of one of several characters.
strspn:
Find the length of an initial span of characters in a given set.
strcspn:
Measure a span of characters not in a given set.
strerror:
Returns a pointer to a message string for an error number.

The following deprecated functions are provided for compatibility with existing code:

bcmp:
Compare two byte strings.
bcopy:
Copy data from one location in memory to another.
bzero:
Clear the contents of a memory block to zero.
ffs:
Find first bit set in a bit string.
index:
Find the first occurrence of a character in a string.
rindex:
Find the last occurrence of a character in a string.
strcasecmp:
Compare two strings, ignoring case.
strncasecmp:
Compare two strings, ignoring case, up to a specified length.
strsep:
Separate strings.

14.4.19 strings.h: string handling functions (deprecated)

DESCRIPTION

For compatibility with existing software, a header file called strings.h is provided which acts as a synonym for string.h (Section 14.4.18).

14.4.20 sys/gmon.h: GNU profiling support definitions

DESCRIPTION

GNU profiling support definitions.

14.4.21 sys/ioctl.h: I/O control definitions

DESCRIPTION

Format definitions for ‘ioctl’ commands. From BSD4.4.

14.4.22 sys/mman.h: memory management and mapping definitions

DESCRIPTION

This file includes constant definitions and function prototypes for memory management operations.

mmap:
Map a file into a region of memory.
mprotect:
Change the protections associated with an mmaped region.
munmap:
Unmap a file from memory.

None of these routines are implemented in the minimal C library.

The defined constant values are the same as traditional BSD, though the values of PROT_READ and PROT_EXEC are reversed.

14.4.23 sys/param.h: system parameters

DESCRIPTION

This file should be included by code that requires certain system- and machine-dependent parameters and functions.

htonl:
Covert a 32-bit value from host byte order to network byte order.
htons:
Covert a 16-bit value from host byte order to network byte order.
ntohl:
Covert a 32-bit value from network byte order to host byte order.
ntohs:
Covert a 16-bit value from network byte order to host byte order.

14.4.24 sys/reboot.h: reboot definitions (deprecated)

DESCRIPTION

Definitions the arguments to the reboot system call.

14.4.25 sys/signal.h: signal handling (deprecated)

DESCRIPTION

This header simply includes the base C library signal.h.

14.4.26 sys/stat.h: file operations

DESCRIPTION

This header includes constant definitions and function prototypes for file operations.

chmod:
Change the access mode of a file.
fchmod:
Change the access mode of a file descriptor.
stat:
Get statistics on a named file.
lstat:
Get statistics on a named file without following symbolic links.
fstat:
Get statistics on an open file by file descriptor.
mkdir:
Create a directory.
mkfifo:
Create a fifo.
mknod:
Create a special file.
umask:
Get/set creation mode mask.

None of these routines are implemented in the minimal C library. Refer to the POSIX library in Section 20.

14.4.27 sys/termios.h: terminal handling functions and definitions (deprecated)

DESCRIPTION

This header simply includes the base C library termio.h.

14.4.28 sys/time.h: timing functions

DESCRIPTION

This header includes constant definitions and function prototypes for timing and related functions, none of which are implemented in the minimal C library. Refer to the POSIX library (Section 20) and the FreeBSD C library (Section 21) for implementation of these functions.

14.4.29 sys/types.h: general POSIX types

DESCRIPTION

General POSIX types.

14.4.30 sys/wait.h: a POSIX wait specification

DESCRIPTION

Note that the minimal C library has no support for processes, and thus doesn’t implement any of the functions prototyped in this header file. The header file is here in case client OSes wish to support POSIX wait semantics.

14.4.31 termios.h: terminal handling functions and definitions

DESCRIPTION

The minimal C library does not fully support termios. Some of the termio stuff is implemented elsewhere to support OSKit devices.

14.4.32 unistd.h: POSIX standard symbolic constants

DESCRIPTION

This file contains the required symbolic constants for a POSIX system. These include the symbolic access and seek constants:

R_OK:
Test for read permission.
W_OK:
Test for write permission.
X_OK:
Test for execute permission.
F_OK:
Test for file existence.
SEEK_SET:
Set file offset to value.
SEEK_CUR:
Set file offset to current plus value.
SEEK_END:
Set file offset to EOF plus value.

This file defines no POSIX compile-time or execution-time constants. Additionally defined are the constants:

STDIN_FILENO:
File descriptor for stdin.
STDOUT_FILENO:
File descriptor for stdout.
STDERR_FILENO:
File descriptor for stderr.

prototypes for standard POSIX functions:

_exit:
Terminate a process.
access:
Check file accessibility.
close:
Close a file.
lseek:
Reposition read/write file offset.
read:
Read from a file.
unlink:
Remove directory entries.
write:
Write to a file.

Of the above routines, only _exit is considered part of the minimal C library. The remaining functions are part of the extended POSIX environment. Refer to Section 20 for details.

14.4.33 utime.h: file times

DESCRIPTION

This file defines the utimbuf structure, as well as the prototype for the POSIX function utime, which sets the access and modification times of a named file. This function is not implemented in the minimal C library. Refer to Section 20 for details.

14.4.34 sys/utsname.h: system identification

DESCRIPTION

This file defines the utsname structure, as well as the prototype for the POSIX function uname, which returns a series of null terminated strings of information identifying the current system. This function is not implemented in the minimal C library. Refer to Section 20 for details.

14.5 Memory Allocation

All of the default memory allocation functions in the minimal C library are built on top of the OSKit LMM, described in Chapter 25.

There are three families of memory allocation routines available in the minimal C library. First is the standard malloc, realloc, calloc, and free. These work as in any standard C library.

The second family, smalloc, smemalign, and sfree, assume that the caller will keep track of the size of allocated memory blocks. Chunks allocated with smalloc-style functions must be freed with sfree rather than the normal free. These functions are not part of the POSIX standard, but are much more memory efficient when allocating many power-of-two-size chunks naturally aligned to their size (e.g., when allocating naturally-aligned pages or superpages). The normal memalign function attaches a prefix to each allocated block to keep track of the block’s size, and the presence of this prefix makes it impossible to allocate naturally-aligned, natural-sized blocks successively in memory; only every other block can be used, greatly increasing fragmentation and effectively halving usable memory. (Note that this fragmentation property is not peculiar to the OSKit’s implementation of memalign; most versions of memalign produce have this effect.)

The third family, mallocf, memalignf, smallocf, and smemalignf, allow LMM flags to be passed to the more common allocation routines. These are useful for allocating memory of a specific type (see 25.2). Memory allocated with these routines should be freed with free or sfree as appropriate.

All of the memory management functions, if they are unable to allocate a block out of the LMM pool, call the morecore function and then retry the allocation if morecore returns non-zero. The default behavior for this function is simply to return 0, signifying that no more memory is available. In environments in which a dynamically growable heap is available, you can override the morecore function to grow the heap as appropriate.

All of the memory allocation functions make calls to mem_lock and mem_unlock to protect access to the LMM pool under all of these services. The default implementation of these synchronization functions in the minimal C library is to do nothing. However, when the C library is initialized (see Section 14.7.1 or Section 21.8.1), a query for the lock manager will be made (See Section 6.3) to determine if there is a default implementation of locks available, and will use that implementation to guarantee thread/SMP safety. The absence of a lock manager implementation implies a single threaded environment, and thus locks are unnecessary. Additionally, they can be overridden with functions that acquire and release a lock of some kind appropriate to the environment in order to make the allocation functions thread- or SMP-safe. Also, note that if you link in liboskit_kern before liboskit_c, the kernel support library provides its own default implementation of mem_lock and mem_unlock, which call base_critical_enter and base_critical_leave respectively; this provides simple and robust, though probably far from optimal, memory allocation protection for kernel code running on the bare hardware.

14.5.1 malloc_lmm: LMM pool used by the default memory allocation functions

SYNOPSIS

#include <oskit/c/malloc.h>

extern lmm_t malloc_lmm;

DESCRIPTION

The LMM pool used by all default memory allocation functions either directly or indirectly.

In the base environemnt, this LMM is initialized at boot time to contain all the physical memory available in the system (see Section 15.11). “Available memory” means all that is not used by base environment data structures or by the OS kernel image itself.

14.5.2 malloc: allocate uninitialized memory

SYNOPSIS

#include <oskit/c/malloc.h>

void *malloc(size_t size);

DESCRIPTION

Standard issue malloc function. Calls mallocf with flags value zero to allocate the memory.

PARAMETERS
size:
Size in bytes of desired allocation.
RETURNS

Returns a pointer to the allocated memory or zero if none.

14.5.3 mustmalloc: allocate uninitialized memory and panic on failure

SYNOPSIS

#include <oskit/c/malloc.h>

void *mustmalloc(size_t size);

DESCRIPTION

Calls malloc to allocate memory, asserting that the return is non-zero; i.e., mustmalloc will panic if no memory is available.

Note that if NDEBUG is defined, assert will do nothing and this routine is identical to malloc.

PARAMETERS
size:
Size in bytes of desired allocation.
RETURNS

Returns a pointer to the allocated memory if it returns at all.

14.5.4 memalign: allocate aligned uninitialized memory

SYNOPSIS

#include <oskit/c/malloc.h>

void *memalign(size_t alignment, size_t size);

DESCRIPTION

Allocate uninitialized memory with the specified byte alignment; e.g., an alignment value of 32 will return a block aligned on a 32-byte boundary. Calls memalignf with flags value zero to allocate the memory.

Note that the alignment is not the same as used by the underlying LMM routines. The alignment parameter in LMM calls is the number of low-order bits that should be zero in the returned pointer.

PARAMETERS
alignment:
Desired byte-alignment of the returned block.
size:
Size in bytes of desired allocation.
RETURNS

Returns a pointer to the allocated memory or zero if none.

14.5.5 calloc: allocate cleared memory

SYNOPSIS

#include <oskit/c/malloc.h>

void *calloc(size_t nelt, size_t eltsize);

DESCRIPTION

Standard issue calloc function. Calls malloc to allocate the memory and memset to clear it.

PARAMETERS
nelt:
Number of elements being allocated.
eltsize:
Size of each element.
RETURNS

Returns a pointer to the allocated memory or zero if none.

14.5.6 mustcalloc: allocate cleared memory and panic on failure

SYNOPSIS

#include <oskit/c/malloc.h>

void *mustcalloc(size_t nelt, size_t eltsize);

DESCRIPTION

Calls calloc to allocate memory, asserting that the return is non-zero; i.e., mustcalloc will panic if no memory is available.

Note that if NDEBUG is defined, assert will do nothing and this routine is identical to calloc.

PARAMETERS
nelt:
Number of elements being allocated.
eltsize:
Size of each element.
RETURNS

Returns a pointer to the allocated memory if it returns at all.

14.5.7 realloc: change the size of an existing memory block

SYNOPSIS

#include <oskit/c/malloc.h>

void *realloc(void *buf, size_t new_size);

DESCRIPTION

Standard issue realloc function. Calls malloc if buf is zero, otherwise calls lmm_alloc to allocate an entirely new block of memory, uses memcpy to copy the old block, and lmm_frees that block when done.

May call morecore if the initial attempt to allocate memory fails.

PARAMETERS
buf :
Pointer to memory to be enlarged.
new_size:
Desired size of resulting block.
RETURNS

Returns a pointer to the allocated memory or zero if none.

14.5.8 free: release an allocated memory block

SYNOPSIS

#include <oskit/c/malloc.h>

void free(void *buf);

DESCRIPTION

Standard issue free function. Calls lmm_free to release the memory.

Note that free must only be called with memory allocated by one of: malloc, realloc, calloc, mustmalloc, mustcalloc, mallocf, memalign, or memalignf.

PARAMETERS
buf :
Pointer to memory to be freed.

14.5.9 smalloc: allocated uninitialized memory with explicit size

SYNOPSIS

#include <oskit/c/malloc.h>

void *smalloc(size_t size);

DESCRIPTION

Identical to malloc except that the user must keep track of the size of the allocated chunk and pass that size to sfree when releasing the chunk.

Calls smallocf with flags value zero to allocate the memory.

PARAMETERS
size:
Size in bytes of desired allocation.
RETURNS

Returns a pointer to the allocated memory or zero if none.

14.5.10 smemalign: allocate aligned memory with explicit size

SYNOPSIS

#include <oskit/c/malloc.h>

void *smemalign(size_t alignment, size_t size);

DESCRIPTION

Identical to memalign except that the user must keep track of the size of the allocated chunk and pass that size to sfree when releasing the chunk.

Allocates uninitialized memory with the specified byte alignment; e.g., an alignment value of 32 will return a block aligned on a 32-byte boundary. Calls smemalignf with flags value zero to allocate the memory.

Note that the alignment is not the same as used by the underlying LMM routines. The alignment parameter in LMM calls is the number of low-order bits that should be zero in the returned pointer.

PARAMETERS
alignment:
Desired byte-alignment of the returned block.
size:
Size in bytes of desired allocation.
RETURNS

Returns a pointer to the allocated memory or zero if none.

14.5.11 sfree: release a memory block with explicit size

SYNOPSIS

#include <oskit/c/malloc.h>

void sfree(void *buf, size_t size);

DESCRIPTION

Frees a block of memory with the indicated size. Calls lmm_free to release the memory.

Note that sfree must only be called with memory allocated by one of: smalloc, smallocf, smemalign, or smemalignf and that the size given must match that used on allocation.

PARAMETERS
buf :
Pointer to memory to be freed.
size:
Size of memory block being freed.

14.5.12 mallocf: allocate uninitialized memory with explicit LMM flags

SYNOPSIS

#include <oskit/c/malloc.h>

void *mallocf(size_t size, unsigned int flags);

DESCRIPTION

Allocates uninitialized memory from malloc_lmm. The interface is similar to malloc but with an additional flags parameter which is passed to lmm_alloc.

For kernels running in the base environment on an x86, meaningful values for flags are as described in Section 15.11.1.

PARAMETERS
size:
Size in bytes of desired allocation.
flags:
Flags to pass to lmm_alloc.
RETURNS

Returns a pointer to the allocated memory or zero if none.

14.5.13 memalignf: allocate aligned uninitialized memory with explict LMM flags

SYNOPSIS

#include <oskit/c/malloc.h>

void *memalignf(size_t alignment, size_t size, unsigned int flags);

DESCRIPTION

Allocate uninitialized memory with the specified byte alignment; e.g., an alignment value of 32 will return a block aligned on a 32-byte boundary. The interface is similar to malloc but with an additional flags parameter which is passed to lmm_alloc.

For kernels running in the base environment on an x86, meaningful values for flags are as described in Section 15.11.1.

Note that the alignment is not the same as used by the underlying LMM routines. The alignment parameter in LMM calls is the number of low-order bits that should be zero in the returned pointer.

PARAMETERS
alignment:
Desired byte-alignment of the returned block.
size:
Size in bytes of desired allocation.
flags:
Flags to pass to lmm_alloc.
RETURNS

Returns a pointer to the allocated memory or zero if none.

14.5.14 smallocf: allocated uninitialized memory with explicit size and LMM flags

SYNOPSIS

#include <oskit/c/malloc.h>

void *smallocf(size_t size, unsigned int flags);

DESCRIPTION

Allocates uninitialized memory from malloc_lmm. The interface is similar to smalloc but with an additional flags parameter which is passed to lmm_alloc. As with smalloc, the user must keep track of the size of the allocated chunk and pass that size to sfree when releasing the chunk.

For kernels running in the base environment on an x86, meaningful values for flags are as described in Section 15.11.1.

PARAMETERS
size:
Size in bytes of desired allocation.
flags:
Flags to pass to lmm_alloc.
RETURNS

Returns a pointer to the allocated memory or zero if none.

14.5.15 smemalignf: allocate aligned memory with explicit size and LMM flags

SYNOPSIS

#include <oskit/c/malloc.h>

void *smemalignf(size_t alignment, size_t size, unsigned int flags);

DESCRIPTION

Allocate uninitialized memory with the specified byte alignment; e.g., an alignment value of 32 will return a block aligned on a 32-byte boundary. The interface is similar to smemalign but with an additional flags parameter which is passed to lmm_alloc. As with smemalign, the user must keep track of the size of the allocated chunk and pass that size to sfree when releasing the chunk.

For kernels running in the base environment on an x86, meaningful values for flags are as described in Section 15.11.1.

Note that the alignment is not the same as used by the underlying LMM routines. The alignment parameter in LMM calls is the number of low-order bits that should be zero in the returned pointer.

PARAMETERS
alignment:
Desired byte-alignment of the returned block.
size:
Size in bytes of desired allocation.
flags:
Flags to pass to lmm_alloc.
RETURNS

Returns a pointer to the allocated memory or zero if none.

14.5.16 morecore: add memory to malloc memory pool

SYNOPSIS

#include <oskit/c/malloc.h>

int morecore(size_t size);

DESCRIPTION

This routine is called directly or indirectly by any of the memory allocation routines in this section when a call to the underlying LMM allocation routine fails. This allows a kernel to add more memory to malloc_lmm as needed.

The default version of morecore in the minimal C library just returns zero indicating no more memory was available. Client OSes should override this routine as necessary.

PARAMETERS
size:
Size in bytes of memory that should be addeed to malloc_lmm.
RETURNS

Returns non-zero if the indicated amount of memory was added, zero otherwise.

14.5.17 mem_lock: Lock access to malloc memory pool

SYNOPSIS

#include <oskit/c/malloc.h>

void mem_lock(void);

DESCRIPTION

This routine is called from any default memory allocation routine before it attempts to access malloc_lmm.

Coupled with mem_unlock, this provides a way to make memory allocation thread and MP safe. In a multithreaded client OS, these functions will use the default lock implementation as provided by the lock manager (see Section 6.3), to protect accesses to the malloc_lmm. Or, these functions may be overridden with a suitable synchronization primitive.

Note that the kernel support library provides defaults for mem_lock and mem_unlock that call base_critical_enter and base_critical_leave respectively. However, you’ll only get these versions if you use the kernel support library and link it in before the minimal C library.

14.5.18 mem_unlock: Unlock access to malloc memory pool

SYNOPSIS

#include <oskit/c/malloc.h>

void mem_unlock(void);

DESCRIPTION

This routine is called from any default memory allocation routine after all accesses to malloc_lmm are complete.

Coupled with mem_lock, this provides a way to make memory allocation thread and MP safe. In a multithreaded client OS, these functions will use the default lock implementation as provided by the lock manager (see Section 6.3), to protect accesses to the malloc_lmm. Or, these functions may be overridden with a suitable synchronization primitive.

Note that the kernel support library provides defaults for mem_lock and mem_unlock that call base_critical_enter and base_critical_leave respectively. However, you’ll only get these versions if you use the kernel support library and link it in before the minimal C library.

14.6 Standard I/O Functions

The versions of sprintf, vsprintf, sscanf, and vsscanf provided in the OSKit’s minimal C library are completely self-contained; they do not pull in the code for printf, fprintf, or other “file-oriented” standard I/O functions. Thus, they can be used in any environment, regardless of whether some kind of console or file I/O is available.

The routines printf, puts, putchar, getchar, etc., are all defined in terms of console_putchar, console_getchar, console_puts, and console_putbytes. This means that you can get working formatted “console” output merely by providing an appropriate implementation of the aforementioned console functions. In the base environment, these routines are defined in the kernel library (see Section 15.13).

The standard I/O functions that actually take a FILE* argument, such as fprintf and fwrite, and as such are fundamentally dependent on the notion of files, are implemented in terms of the low-level I/O functions in the POSIX library (see Section 20). However, unlike in “real” C libraries, the high-level file I/O functions provided by the minimal C library only implement the minimum of functionality to provide the basic API: in particular, they do no buffering, so for example an fwrite translates directly to a write. This design reduces code size and minimizes interdependencies between functions, while still providing familiar, useful services such as formatted file I/O.

14.7 Initialization

14.7.1 oskit_init_libc: Load the OSKit C library

SYNOPSIS

#include <oskit/c/fs.h>

void oskit_load_libc(oskit_services_t *services);

DESCRIPTION

oskit_load_libc allows for internal initializatons to be done. This routine must be called when the operating system is initialized, typically from the Client OS library. The services database is used to lookup other interfaces required by the C library, and is maintained as internal state to the library.

PARAMETERS
services:
A reference to a services database preloaded with interfaces required by the C library.

14.7.2 oskit_init_libc: Initialize the OSKit C library

SYNOPSIS

void oskit_init_libc(void);

DESCRIPTION

oskit_init_libc allows for secondary initializations to be performed by the C library, in cases where lazy initialization is not appropriate. It must be called sometime after oskit_load_libc.

14.8 Termination Functions

14.8.1 exit: terminate normally

DESCRIPTION

exit calls up to 32 functions installed via atexit in reverse order of installation before it calls _exit.

_exit, which terminates the calling process in Unix, calls oskit_libc_exit with the exit status code (see Section 20.5.1).

14.8.2 abort: terminate abnormally

DESCRIPTION

abort calls _exit(1).

14.8.3 panic: terminate abnormally with an error message

14.9 Miscellaneous Functions

14.9.1 hexdump: print a buffer as a hexdump

SYNOPSIS

#include <oskit/c/stdio.h>

void hexdumpb(void *base, void *buf, int nbytes);
void hexdumpw(void *base, void *buf, int nwords);

DESCRIPTION

These functions print out a buffer as a hexdump. For example (the box is included):

 .---------------------------------------------------------------------------.
 | 00000000       837c240c 00741dc7 05007010 00000000       .|$..t....p..... |
 | 00000010       008b4424 0ca30470 10008b04 24a30870       ..D$...p....$..p |
 | 00000020       1000eb2c c7050070 10000100 0000833c       ...,...p.......< |
 | 00000030       2400740a c7050070 10000200 00008b44       $.t....p.......D |
 `---------------------------------------------------------------------------'
         

The first form treats the buffer as an array of bytes whereas the second treats the buffer as an array of words. This distinction is only important on little-endian machines and only affects the appearance of the four middle columns of hex numbers--the last column of output is identical for both.

PARAMETERS
base:
What the first column of output should start at. Passing zero will make the first column show the offset within the buffer rather than an absolute address, which is what happens when base equals buf.
buf :
The address of what to dump.
nbytes:
How many bytes to dump.
nwords:
How many words to dump.

14.9.2 sigcontext_dump: dump machine specific sigcontext structure

SYNOPSIS

#include <oskit/c/signal.h>

void sigcontext_dump(struct sigcontext *scp);

DESCRIPTION

Dump machine-specific state from a sigcontext structure to stdout. On the x86 this includes the processor registers and a stack backtrace originating at the saved EBP value.

PARAMETERS
scp:
Pointer to sigcontext structure to dump.