libc: remove global constructors

- readv_writev: move 'rw_lock' instance into a function scope,
  constructing the instance on the first access.
- select: move 'select_cb_list' instance into function scope.
- thread: move 'key_list_lock' and 'keys' into function scope.
- rwlock, semaphore, socket_fs_plugin, thread, thread_create:
  instantiate 'Libc::Allocator' per use, alleviating the need for a
  global instance.

Issue #3496
This commit is contained in:
Norman Feske 2019-09-16 13:52:39 +02:00 committed by Christian Helmuth
parent 4a7b0e99a6
commit 0aedabd245
7 changed files with 125 additions and 94 deletions

View File

@ -23,9 +23,6 @@
#include <stdio.h>
static Genode::Lock rw_lock;
struct Read
{
ssize_t operator()(int fd, void *buf, size_t count)
@ -44,10 +41,17 @@ struct Write
};
static Genode::Lock &rw_lock()
{
static Genode::Lock rw_lock;
return rw_lock;
}
template <typename Rw_func>
static ssize_t readv_writev_impl(Rw_func rw_func, int fd, const struct iovec *iov, int iovcnt)
{
Genode::Lock_guard<Genode::Lock> rw_lock_guard(rw_lock);
Genode::Lock_guard<Genode::Lock> rw_lock_guard(rw_lock());
char *v;
ssize_t bytes_transfered_total = 0;

View File

@ -24,9 +24,6 @@
#include <pthread.h>
static Libc::Allocator object_alloc;
/*
* A reader-preferring implementation of a readers-writer lock as described
* in Michael Raynal, "Concurrent Programming: Algorithms, Principles, and
@ -105,7 +102,8 @@ extern "C" {
try {
Genode::Lock::Guard g(rwlock_init_lock);
*rwlock = new (object_alloc) struct pthread_rwlock();
Libc::Allocator alloc { };
*rwlock = new (alloc) struct pthread_rwlock();
return 0;
} catch (...) { return ENOMEM; }
}
@ -117,7 +115,8 @@ extern "C" {
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
{
destroy(object_alloc, *rwlock);
Libc::Allocator alloc { };
destroy(alloc, *rwlock);
return 0;
}
@ -154,7 +153,8 @@ extern "C" {
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
{
*attr = new (object_alloc) struct pthread_rwlockattr();
Libc::Allocator alloc { };
*attr = new (alloc) struct pthread_rwlockattr();
return 0;
}
@ -175,7 +175,8 @@ extern "C" {
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
{
destroy(object_alloc, *attr);
Libc::Allocator alloc { };
destroy(alloc, *attr);
return 0;
}

View File

@ -69,7 +69,7 @@ struct Libc::Select_cb_list
struct Guard : Genode::Lock::Guard
{
Select_cb_list *l;
Select_cb_list *l;
Guard(Select_cb_list &list) : Genode::Lock::Guard(list._mutex), l(&list) { }
};
@ -110,7 +110,11 @@ Select_cb_list *l;
};
/** The global list of tasks waiting for select */
static Libc::Select_cb_list select_cb_list;
static Libc::Select_cb_list &select_cb_list()
{
static Libc::Select_cb_list inst;
return inst;
}
/**
@ -183,7 +187,7 @@ static void select_notify()
/* check for each waiting select() function if one of its fds is ready now
* and if so, wake all up */
select_cb_list.for_each([&] (Libc::Select_cb &scb) {
select_cb_list().for_each([&] (Libc::Select_cb &scb) {
scb.nready = selscan(scb.nfds,
&scb.readfds, &scb.writefds, &scb.exceptfds,
&tmp_readfds, &tmp_writefds, &tmp_exceptfds);
@ -236,7 +240,7 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
* We use the guard directly to atomically check if any descripor is
* ready, but insert into select-callback list otherwise.
*/
Libc::Select_cb_list::Guard guard(select_cb_list);
Libc::Select_cb_list::Guard guard(select_cb_list());
int const nready = selscan(nfds,
&in_readfds, &in_writefds, &in_exceptfds,
@ -254,7 +258,7 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
select_cb.construct(nfds, in_readfds, in_writefds, in_exceptfds);
select_cb_list.unsynchronized_insert(&(*select_cb));
select_cb_list().unsynchronized_insert(&(*select_cb));
}
struct Timeout
@ -283,7 +287,7 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
while (!timeout.expired() && select_cb->nready == 0)
timeout.duration = Libc::suspend(check, timeout.duration);
select_cb_list.remove(&(*select_cb));
select_cb_list().remove(&(*select_cb));
if (timeout.expired())
return 0;
@ -352,14 +356,14 @@ int Libc::Select_handler_base::select(int nfds, fd_set &readfds,
/* remove potentially enqueued callback from list */
if (_select_cb->constructed())
select_cb_list.remove(&(**_select_cb));
select_cb_list().remove(&(**_select_cb));
{
/*
* We use the guard directly to atomically check is any descripor is
* ready, and insert into select-callback list otherwise.
*/
Libc::Select_cb_list::Guard guard(select_cb_list);
Libc::Select_cb_list::Guard guard(select_cb_list());
int const nready = selscan(nfds,
&in_readfds, &in_writefds, &in_exceptfds,
@ -373,7 +377,7 @@ int Libc::Select_handler_base::select(int nfds, fd_set &readfds,
_select_cb->construct(nfds, in_readfds, in_writefds, in_exceptfds);
select_cb_list.unsynchronized_insert(&(**_select_cb));
select_cb_list().unsynchronized_insert(&(**_select_cb));
}
Libc::schedule_select(this);
@ -388,7 +392,7 @@ void Libc::Select_handler_base::dispatch_select()
if (select_cb->nready == 0) return;
select_cb_list.remove(&(*select_cb));
select_cb_list().remove(&(*select_cb));
Libc::schedule_select(nullptr);
select_ready(select_cb->nready, select_cb->readfds,

View File

@ -20,8 +20,6 @@
using namespace Genode;
static Libc::Allocator object_alloc;
extern "C" {
/*
@ -43,7 +41,8 @@ extern "C" {
int sem_destroy(sem_t *sem)
{
destroy(object_alloc, *sem);
Libc::Allocator alloc { };
destroy(alloc, *sem);
return 0;
}
@ -57,7 +56,8 @@ extern "C" {
int sem_init(sem_t *sem, int pshared, unsigned int value)
{
*sem = new (object_alloc) struct sem(value);
Libc::Allocator alloc { };
*sem = new (alloc) struct sem(value);
return 0;
}

View File

@ -54,8 +54,6 @@ namespace Libc {
namespace Socket_fs {
Libc::Allocator global_allocator;
using Libc::Errno;
struct Absolute_path : Vfs::Absolute_path
@ -542,7 +540,8 @@ extern "C" int socket_fs_accept(int libc_fd, sockaddr *addr, socklen_t *addrlen)
Socket_fs::Context *accept_context;
try {
accept_context = new (&global_allocator)
Libc::Allocator alloc { };
accept_context = new (alloc)
Socket_fs::Context(listen_context->proto(), handle_fd);
} catch (New_socket_failed) { return Errno(EACCES); }
@ -962,7 +961,8 @@ extern "C" int socket_fs_socket(int domain, int type, int protocol)
Genode::error("failed to open new socket at ", path);
return Errno(EACCES);
}
context = new (&global_allocator)
Libc::Allocator alloc { };
context = new (alloc)
Socket_fs::Context(proto, handle_fd);
} catch (New_socket_failed) { return Errno(EACCES); }
@ -1004,9 +1004,10 @@ extern "C" int getifaddrs(struct ifaddrs **ifap)
static sockaddr_in address;
static sockaddr_in netmask { 0 };
static sockaddr_in broadcast { 0 };
static char name[1] { };
static ifaddrs ifaddr {
.ifa_name = "",
.ifa_name = name,
.ifa_flags = IFF_UP,
.ifa_addr = (sockaddr*)&address,
.ifa_netmask = (sockaddr*)&netmask,
@ -1188,7 +1189,8 @@ int Socket_fs::Plugin::close(Libc::File_descriptor *fd)
Socket_fs::Context *context = dynamic_cast<Socket_fs::Context *>(fd->context);
if (!context) return Errno(EBADF);
Genode::destroy(&global_allocator, context);
Libc::Allocator alloc { };
Genode::destroy(alloc, context);
Libc::file_descriptor_allocator()->free(fd);
/*

View File

@ -29,14 +29,17 @@
using namespace Genode;
static Libc::Allocator object_alloc;
static Env *_env_ptr; /* solely needed to spawn the timeout thread for the
timed semaphore */
static Thread *_main_thread_ptr;
void Libc::init_pthread_support(Genode::Env &env) { _env_ptr = &env; }
void Libc::init_pthread_support(Genode::Env &env)
{
_env_ptr = &env;
_main_thread_ptr = Thread::myself();
}
static Libc::Timeout_entrypoint &_global_timeout_ep()
@ -50,19 +53,6 @@ static Libc::Timeout_entrypoint &_global_timeout_ep()
}
/*
* We initialize the main-thread pointer in a constructor depending on the
* assumption that libpthread is loaded on application startup by ldso. During
* this stage only the main thread is executed.
*/
static __attribute__((constructor)) Thread * main_thread()
{
static Thread *thread = Thread::myself();
return thread;
}
/*
* pthread
*/
@ -172,7 +162,8 @@ extern "C" {
{
thread->join(retval);
destroy(object_alloc, thread);
Libc::Allocator alloc { };
destroy(alloc, thread);
return 0;
}
@ -183,7 +174,8 @@ extern "C" {
if (!attr)
return EINVAL;
*attr = new (object_alloc) pthread_attr;
Libc::Allocator alloc { };
*attr = new (alloc) pthread_attr;
return 0;
}
@ -194,7 +186,8 @@ extern "C" {
if (!attr || !*attr)
return EINVAL;
destroy(object_alloc, *attr);
Libc::Allocator alloc { };
destroy(alloc, *attr);
*attr = 0;
return 0;
@ -218,7 +211,7 @@ extern "C" {
/* special non-POSIX function (for example used in libresolv) */
int _pthread_main_np(void)
{
return (Thread::myself() == main_thread());
return (Thread::myself() == _main_thread_ptr);
}
@ -251,7 +244,8 @@ extern "C" {
* of the pthread object would also destruct the 'Thread' of the main
* thread.
*/
static pthread *main = new (object_alloc) pthread(*Thread::myself());
Libc::Allocator alloc { };
static pthread *main = new (alloc) pthread(*Thread::myself());
return main;
}
@ -498,7 +492,8 @@ extern "C" {
if (!attr)
return EINVAL;
*attr = new (object_alloc) pthread_mutex_attr;
Libc::Allocator alloc { };
*attr = new (alloc) pthread_mutex_attr;
return 0;
}
@ -509,7 +504,8 @@ extern "C" {
if (!attr || !*attr)
return EINVAL;
destroy(object_alloc, *attr);
Libc::Allocator alloc { };
destroy(alloc, *attr);
*attr = 0;
return 0;
@ -533,7 +529,8 @@ extern "C" {
if (!mutex)
return EINVAL;
*mutex = new (object_alloc) pthread_mutex(attr);
Libc::Allocator alloc { };
*mutex = new (alloc) pthread_mutex(attr);
return 0;
}
@ -544,7 +541,8 @@ extern "C" {
if ((!mutex) || (*mutex == PTHREAD_MUTEX_INITIALIZER))
return EINVAL;
destroy(object_alloc, *mutex);
Libc::Allocator alloc { };
destroy(alloc, *mutex);
*mutex = PTHREAD_MUTEX_INITIALIZER;
return 0;
@ -655,7 +653,8 @@ extern "C" {
try {
Genode::Lock::Guard g(cond_init_lock);
*cond = new (object_alloc) pthread_cond;
Libc::Allocator alloc { };
*cond = new (alloc) pthread_cond;
return 0;
} catch (...) { return ENOMEM; }
}
@ -673,7 +672,8 @@ extern "C" {
if (!cond || !*cond)
return EINVAL;
destroy(object_alloc, *cond);
Libc::Allocator alloc { };
destroy(alloc, *cond);
*cond = 0;
return 0;
@ -838,24 +838,42 @@ extern "C" {
};
static Lock key_list_lock;
List<Key_element> key_list[PTHREAD_KEYS_MAX];
static Lock &key_list_lock()
{
static Lock inst { };
return inst;
}
struct Keys
{
List<Key_element> key[PTHREAD_KEYS_MAX];
};
static Keys &keys()
{
static Keys inst { };
return inst;
}
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
{
if (!key)
return EINVAL;
Lock_guard<Lock> key_list_lock_guard(key_list_lock);
Lock_guard<Lock> key_list_lock_guard(key_list_lock());
for (int k = 0; k < PTHREAD_KEYS_MAX; k++) {
/*
* Find an empty key slot and insert an element for the current
* thread to mark the key slot as used.
*/
if (!key_list[k].first()) {
Key_element *key_element = new (object_alloc) Key_element(Thread::myself(), 0);
key_list[k].insert(key_element);
if (!keys().key[k].first()) {
Libc::Allocator alloc { };
Key_element *key_element = new (alloc) Key_element(Thread::myself(), 0);
keys().key[k].insert(key_element);
*key = k;
return 0;
}
@ -867,14 +885,15 @@ extern "C" {
int pthread_key_delete(pthread_key_t key)
{
if (key < 0 || key >= PTHREAD_KEYS_MAX || !key_list[key].first())
if (key < 0 || key >= PTHREAD_KEYS_MAX || !keys().key[key].first())
return EINVAL;
Lock_guard<Lock> key_list_lock_guard(key_list_lock);
Lock_guard<Lock> key_list_lock_guard(key_list_lock());
while (Key_element * element = key_list[key].first()) {
key_list[key].remove(element);
destroy(object_alloc, element);
while (Key_element * element = keys().key[key].first()) {
keys().key[key].remove(element);
Libc::Allocator alloc { };
destroy(alloc, element);
}
return 0;
@ -888,9 +907,9 @@ extern "C" {
void *myself = Thread::myself();
Lock_guard<Lock> key_list_lock_guard(key_list_lock);
Lock_guard<Lock> key_list_lock_guard(key_list_lock());
for (Key_element *key_element = key_list[key].first(); key_element;
for (Key_element *key_element = keys().key[key].first(); key_element;
key_element = key_element->next())
if (key_element->thread_base == myself) {
key_element->value = value;
@ -898,8 +917,9 @@ extern "C" {
}
/* key element does not exist yet - create a new one */
Key_element *key_element = new (object_alloc) Key_element(Thread::myself(), value);
key_list[key].insert(key_element);
Libc::Allocator alloc { };
Key_element *key_element = new (alloc) Key_element(Thread::myself(), value);
keys().key[key].insert(key_element);
return 0;
}
@ -911,9 +931,9 @@ extern "C" {
void *myself = Thread::myself();
Lock_guard<Lock> key_list_lock_guard(key_list_lock);
Lock_guard<Lock> key_list_lock_guard(key_list_lock());
for (Key_element *key_element = key_list[key].first(); key_element;
for (Key_element *key_element = keys().key[key].first(); key_element;
key_element = key_element->next())
if (key_element->thread_base == myself)
return (void*)(key_element->value);
@ -929,7 +949,8 @@ extern "C" {
return EINTR;
if (!once->mutex) {
pthread_mutex_t p = new (object_alloc) pthread_mutex(0);
Libc::Allocator alloc { };
pthread_mutex_t p = new (alloc) pthread_mutex(0);
/* be paranoid */
if (!p)
return EINTR;
@ -948,7 +969,7 @@ extern "C" {
* free our mutex since it is not used.
*/
if (p)
destroy(object_alloc, p);
destroy(alloc, p);
}
once->mutex->lock();

View File

@ -21,37 +21,36 @@
#include <errno.h>
static Libc::Allocator object_alloc;
int Libc::pthread_create(pthread_t *thread,
void *(*start_routine) (void *), void *arg,
size_t stack_size, char const * name,
Genode::Cpu_session * cpu, Genode::Affinity::Location location)
{
pthread_t thread_obj = new (object_alloc)
pthread(start_routine, arg,
stack_size, name, cpu, location);
if (!thread_obj)
return EAGAIN;
Libc::Allocator alloc { };
pthread_t thread_obj = new (alloc)
pthread(start_routine, arg,
stack_size, name, cpu, location);
if (!thread_obj)
return EAGAIN;
*thread = thread_obj;
*thread = thread_obj;
thread_obj->start();
thread_obj->start();
return 0;
return 0;
}
int Libc::pthread_create(pthread_t *thread, Genode::Thread &t)
{
pthread_t thread_obj = new (object_alloc) pthread(t);
Libc::Allocator alloc { };
pthread_t thread_obj = new (alloc) pthread(t);
if (!thread_obj)
return EAGAIN;
if (!thread_obj)
return EAGAIN;
*thread = thread_obj;
return 0;
*thread = thread_obj;
return 0;
}