LibC: Implement pthread_atfork

Again this code is not tested but *feels* right :D
This commit is contained in:
2025-06-01 01:41:09 +03:00
parent dbdefa0f4a
commit df7f245cf8
3 changed files with 107 additions and 1 deletions

View File

@@ -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();