What do we mean by libc?
On Posix-y systems, programs link against a library (either
dynamically or statically) called libc. This library provides the
functions defined by the C standard, as well as the runtime
environment for C programs. Many systems also define other
platform-specific interfaces in the same library. Many of these
interfaces are the preferred way for userspace to access kernel
functionality. For example, Posix-y systems have an open
function in
their libc, which calls an open
system call. Sometimes these are
cross-platform standards, such as pthreads. Others are interfaces to
kernel-specific functionality, such as epoll
or kqueue
. In any
case, this library is present on the system itself and is a stable
interface. In contrast, Windows does not provide a systemwide libc in
its stable win32 interface.
On Fuchsia the story is a bit different from Posix systems. First, the
Zircon kernel (Fuchsia's kernel) does not provide a typical
Posix system call interface. So a Posix function like open
can't
call a Zircon open
syscall. Secondly, Fuchsia implements some parts
of Posix, but omits large parts of the Posix model. Most conspicuously
absent are signals, fork, and exec. Third, Fuchsia does not require
that programs use libc's ABI. Programs are free to use their own libc,
or to do without. However, Fuchsia does provide a libc.so that
programs can dynamically link, which provides implementations both of
the C standard library and of the parts of Posix Fuchsia supports, as
typical Posix systems do.
Piece by piece
This is a partial list of what is implemented (or not) in Fuchsia's libc.
The C standard library
Fuchsia's libc implements the C11 standard. In particular this
includes the threading-related interfaces such as threads (thrd_t
)
and mutexes (mtx_t
). A small handful of extensions are also in this
portion of the system to bridge the C11 structures, like a thrd_t
,
to underlying kernel structures, like the zx_handle_t
underlying it.
Posix
Posix defines a number of interfaces. These include (not exhaustively): file I/O, BSD sockets, and pthreads.
File I/O and BSD sockets
Recall that Zircon is a kernel that is not in the business of
implementing file I/O. Instead, other Fuchsia userspace services
provide filesystems. libc itself defines weak symbols for Posix file
I/O functions such as open
, write
, and fstat
. However, all these
calls simply fail. In addition to libc.so, programs can link the
fdio.so library. fdio knows how to speak to those other Fuchsia
services over
Channel IPC, and
provides a Posix-like layer for libc to expose. Sockets are similarly
implemented via fdio communicating with the userspace network stack.
pthreads
Fuchsia's libc provides parts of the pthread standard. In particular,
the core parts of pthread_t
(those that map straightforwardly onto
the corresponding C11 concepts) and synchronization primitives like
pthread_mutex_t
are provided. Some details, like process-shared
mutexes, are not implemented. The implemented subset does not aim to
be comprehensive.
Signals
Fuchsia does not have Unix-style signals. Zircon provides no way to directly implement them (the kernel provides no way to cause another thread to jump off its context of execution). Fuchsia's libc does not, therefore, have a notion of signal-safe functions, and is not implemented internally to be aware of mechanisms like signals.
Because of this fact, libc functions will not EINTR
, and it is not
necessary for Fuchsia-only code to consider that case. However, it is
perfectly safe to do so. Fuchsia still defines the EINTR
constant,
and code written for both Posix and Fuchsia may still have
EINTR
-handling loops.
fork and exec
Zircon does not have fork or exec. Instead, process creation is
provided by fdio. While Zircon has Process and
Thread objects, these are pretty raw and know nothing about
ELF. The fdio_spawn
function family knows how to turn an ELF binary and some
initial state into a running process.