LibC: Implement pthread_atfork
Again this code is not tested but *feels* right :D
This commit is contained in:
parent
dbdefa0f4a
commit
df7f245cf8
|
@ -82,6 +82,11 @@ struct uthread
|
|||
#define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t){ { PTHREAD_MUTEX_DEFAULT, 0 }, 0, 0 }
|
||||
#define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t){ { 0 }, 0, 0 }
|
||||
|
||||
#define _PTHREAD_ATFORK_PREPARE 0
|
||||
#define _PTHREAD_ATFORK_PARENT 1
|
||||
#define _PTHREAD_ATFORK_CHILD 2
|
||||
void _pthread_call_atfork(int state);
|
||||
|
||||
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void));
|
||||
int pthread_attr_destroy(pthread_attr_t* attr);
|
||||
int pthread_attr_getdetachstate(const pthread_attr_t* attr, int* detachstate);
|
||||
|
|
|
@ -470,6 +470,102 @@ int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct pthread_atfork_t
|
||||
{
|
||||
void (*function)();
|
||||
pthread_atfork_t* next;
|
||||
};
|
||||
static pthread_atfork_t* s_atfork_prepare = nullptr;
|
||||
static pthread_atfork_t* s_atfork_parent = nullptr;
|
||||
static pthread_atfork_t* s_atfork_child = nullptr;
|
||||
static pthread_mutex_t s_atfork_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void _pthread_call_atfork(int state)
|
||||
{
|
||||
pthread_mutex_lock(&s_atfork_mutex);
|
||||
|
||||
pthread_atfork_t* list = nullptr;
|
||||
switch (state)
|
||||
{
|
||||
case _PTHREAD_ATFORK_PREPARE: list = s_atfork_prepare; break;
|
||||
case _PTHREAD_ATFORK_PARENT: list = s_atfork_parent; break;
|
||||
case _PTHREAD_ATFORK_CHILD: list = s_atfork_child; break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
for (; list; list = list->next)
|
||||
list->function();
|
||||
|
||||
pthread_mutex_unlock(&s_atfork_mutex);
|
||||
}
|
||||
|
||||
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void))
|
||||
{
|
||||
pthread_atfork_t* prepare_entry = nullptr;
|
||||
if (prepare != nullptr)
|
||||
prepare_entry = static_cast<pthread_atfork_t*>(malloc(sizeof(pthread_attr_t)));
|
||||
|
||||
pthread_atfork_t* parent_entry = nullptr;
|
||||
if (parent != nullptr)
|
||||
parent_entry = static_cast<pthread_atfork_t*>(malloc(sizeof(pthread_attr_t)));
|
||||
|
||||
pthread_atfork_t* child_entry = nullptr;
|
||||
if (child != nullptr)
|
||||
child_entry = static_cast<pthread_atfork_t*>(malloc(sizeof(pthread_attr_t)));
|
||||
|
||||
if ((prepare && !prepare_entry) || (parent && !parent_entry) || (child && !child_entry))
|
||||
{
|
||||
if (prepare_entry)
|
||||
free(prepare_entry);
|
||||
if (parent_entry)
|
||||
free(parent_entry);
|
||||
if (child_entry)
|
||||
free(child_entry);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
const auto prepend_atfork =
|
||||
[](pthread_atfork_t*& list, pthread_atfork_t* entry)
|
||||
{
|
||||
entry->next = list;
|
||||
list = entry;
|
||||
};
|
||||
|
||||
const auto append_atfork =
|
||||
[](pthread_atfork_t*& list, pthread_atfork_t* entry)
|
||||
{
|
||||
while (list)
|
||||
list = list->next;
|
||||
entry->next = nullptr;
|
||||
list = entry;
|
||||
};
|
||||
|
||||
pthread_mutex_lock(&s_atfork_mutex);
|
||||
|
||||
if (prepare_entry)
|
||||
{
|
||||
prepare_entry->function = prepare;
|
||||
prepend_atfork(s_atfork_prepare, prepare_entry);
|
||||
}
|
||||
|
||||
if (parent_entry)
|
||||
{
|
||||
parent_entry->function = parent;
|
||||
append_atfork(s_atfork_parent, parent_entry);
|
||||
}
|
||||
|
||||
if (child_entry)
|
||||
{
|
||||
child_entry->function = parent;
|
||||
append_atfork(s_atfork_child, child_entry);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&s_atfork_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pthread_cancel_handler(int)
|
||||
{
|
||||
uthread* uthread = _get_uthread();
|
||||
|
|
|
@ -423,7 +423,12 @@ int execvp(const char* pathname, char* const argv[])
|
|||
|
||||
pid_t fork(void)
|
||||
{
|
||||
return syscall(SYS_FORK);
|
||||
_pthread_call_atfork(_PTHREAD_ATFORK_PREPARE);
|
||||
const pid_t pid = syscall(SYS_FORK);
|
||||
if (pid == -1)
|
||||
return -1;
|
||||
_pthread_call_atfork(pid ? _PTHREAD_ATFORK_PARENT : _PTHREAD_ATFORK_CHILD);
|
||||
return pid;
|
||||
}
|
||||
|
||||
int pipe(int fildes[2])
|
||||
|
|
Loading…
Reference in New Issue