Overhaul glibc locking (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 26 Apr 2017 19:18:49 +0000 (15:18 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 3 May 2017 16:13:02 +0000 (12:13 -0400)
commitd2e968a533dcc7130f948b511b9f438d502b1824
tree2c7c79b129d5aeff4d215752ff022f797f80f7b2
parent31d6cdd4922be821405e0c482cd1dee4884be5e4
Overhaul glibc locking (XCC)

Previously, we were using the low-level locks (spin_pdr_locks) for almost
everything in glibc.  The libc_lock was a spinlock, etc.  It turns out, the
libc_lock is supposed to be a mutex.

I had a couple cases where the app would yield while holding a libc_lock,
which you cannot do if it is a spinlock.  Specifically, this happened when
calling fclose() on a FILE (holding the old libc_lock), which closed the
underlying FD, when we were using epoll.  The epoll close callback grabs a
uthread mutex.  The fix is to make the libc_lock a uthread mutex too.  No
problem, right?

The problem was malloc was also using those locks, and vcore context calls
malloc and free.  Vcore context code cannot use mutexes.  So our options
were either never to call malloc or free from vcore context, or to use a
different type of lock.  So far, we can get by with malloc using
spin_pdr_locks (the low-level lock (LLL)).

This all does mean that vcore context code cannot call some things from
glibc, such as close(), printf(), or anything using the libc_lock (a
mutex), including the _IO_lock (which is now explicitly a libc_lock (mutex)
and not a spinlock).  Currently, that includes interprocess signal
handlers, which are run from vcore context.  fprintf() to stderr and stdout
will work, but some other signal-safe functions might not.  close() doesn't
work, not because of the libc_lock (fclose() grabs that, not close()), but
because of the close callbacks, which *do* grab mutexes.  And you can't
grab a mutex from vcore context.

There are a few other implications.  malloc() (using a spinlock) relies on
sbrk(), which previously was a libc_lock.  That now needs to be a spinlock.
It is possible for the kernel to block the mmap() call.  If that happens,
userspace will spin until the call completes.  Oh well.

I also sorted out the rtld locks.  Previously, we were doing nothing for
the recursive locks.  If we had threads racing in dlopen(), then we could
corrupt the various data structures in ld.  Yikes!  There might be issues
with those locks still.  I made them spinlocks, since we can't access
parlib objects at all in that code.  (We can access headers).

Now that rtld isn't using the libc_locks, we no longer have anyone calling
into parlib-compat.c's spinlocks, and we can replace that thread-unsafe
code with asserts.

There's probably a few problems with all of this still.  For instance,
maybe we an do something different for ld.so compared to libdl.so.  Who
knows.  At least it's a little better than before.

Rebuild glibc.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/Versions
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/bits/libc-lock.h
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/bits/stdio-lock.h
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/malloc-machine.h
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/parlib-compat.c
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sbrk.c