libs/pthread/pthread_atfork: fulfill implement pthread_atfork function
1. add the pthread_atfork implementation 2. the pthread_atfork implementation are referred to https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_atfork.html Signed-off-by: guoshichao <guoshichao@xiaomi.com>
This commit is contained in:
parent
3524f4b9ce
commit
9d7f349664
@ -255,6 +255,15 @@
|
||||
&entry->member != (list); entry = temp, \
|
||||
temp = container_of(temp->member.next, type, member))
|
||||
|
||||
/* iterates over the list in reverse order, entry should be the container
|
||||
* structure type
|
||||
*/
|
||||
|
||||
#define list_for_every_entry_reverse(list, entry, type, member) \
|
||||
for(entry = container_of((list)->prev, type, member); \
|
||||
&entry->member != (list); \
|
||||
entry = container_of(entry->member.next, type, member))
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/atexit.h>
|
||||
#include <nuttx/fs/fs.h>
|
||||
#include <nuttx/list.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pthread.h>
|
||||
@ -125,6 +126,21 @@ struct getopt_s
|
||||
bool go_binitialized; /* true: getopt() has been initialized */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PTHREAD_ATFORK
|
||||
/* This structure defines the pthread_atfork_s, which is used to manage
|
||||
* the funcs that operates on pthread_atfork() method
|
||||
*/
|
||||
|
||||
struct pthread_atfork_s
|
||||
{
|
||||
CODE void (*prepare)(void);
|
||||
CODE void (*child)(void);
|
||||
CODE void (*parent)(void);
|
||||
|
||||
struct list_node node;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct task_info_s
|
||||
{
|
||||
mutex_t ta_lock;
|
||||
@ -149,6 +165,10 @@ struct task_info_s
|
||||
#ifdef CONFIG_FILE_STREAM
|
||||
struct streamlist ta_streamlist; /* Holds C buffered I/O info */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PTHREAD_ATFORK
|
||||
struct list_node ta_atfork; /* Holds the pthread_atfork_s list */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* struct pthread_cleanup_s *************************************************/
|
||||
|
@ -14,4 +14,10 @@ config PTHREAD_SPINLOCKS
|
||||
---help---
|
||||
Enable support for pthread spinlocks.
|
||||
|
||||
config PTHREAD_ATFORK
|
||||
bool "pthread_atfork support"
|
||||
default n
|
||||
---help---
|
||||
Enable support for pthread_atfork.
|
||||
|
||||
endmenu # pthread support
|
||||
|
@ -22,21 +22,65 @@
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/tls.h>
|
||||
#include <nuttx/lib/lib.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pthread_atfork
|
||||
*
|
||||
* Description:
|
||||
* To register the methods that need to be executed when fork is called
|
||||
* by any thread in a process
|
||||
*
|
||||
* Input Parameters:
|
||||
* prepare - the method that is executed in the parent process before
|
||||
* fork() processing is started
|
||||
* parent - the method that is executed in the parent process after fork()
|
||||
* processing completes
|
||||
* child - the method that is executed in the child process after fork()
|
||||
* processing completes
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, pthread_atfork() returns 0.
|
||||
* On error, pthread_atfork() returns -1.
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int pthread_atfork(CODE void (*prepare)(void),
|
||||
CODE void (*parent)(void),
|
||||
CODE void (*child)(void))
|
||||
{
|
||||
/* fork isn't supported yet, so the dummy implementation is enough. */
|
||||
#ifdef CONFIG_PTHREAD_ATFORK
|
||||
FAR struct task_info_s *info = task_get_info();
|
||||
FAR struct list_node *list = &info->ta_atfork;
|
||||
FAR struct pthread_atfork_s *entry =
|
||||
(FAR struct pthread_atfork_s *)
|
||||
lib_malloc(sizeof(struct pthread_atfork_s));
|
||||
|
||||
UNUSED(prepare);
|
||||
UNUSED(parent);
|
||||
UNUSED(child);
|
||||
|
||||
return 0;
|
||||
if (entry == NULL)
|
||||
{
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
list_initialize(&entry->node);
|
||||
entry->prepare = prepare;
|
||||
entry->parent = parent;
|
||||
entry->child = child;
|
||||
|
||||
nxmutex_lock(&info->ta_lock);
|
||||
list_add_head(list, &entry->node);
|
||||
nxmutex_unlock(&info->ta_lock);
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
@ -24,11 +24,109 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/tls.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(CONFIG_ARCH_HAVE_FORK)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_PTHREAD_ATFORK
|
||||
/****************************************************************************
|
||||
* Name: atfork_prepare
|
||||
*
|
||||
* Description:
|
||||
* Invoke this method in the parent process before fork starts
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void atfork_prepare(void)
|
||||
{
|
||||
FAR struct task_info_s *info = task_get_info();
|
||||
FAR struct list_node *list = &info->ta_atfork;
|
||||
FAR struct pthread_atfork_s *entry;
|
||||
|
||||
/* According to posix standard, the prepare handlers are called in reverse
|
||||
* order of registration
|
||||
* so we iterate over the func list in reverse order
|
||||
*/
|
||||
|
||||
nxmutex_lock(&info->ta_lock);
|
||||
list_for_every_entry_reverse(list, entry,
|
||||
struct pthread_atfork_s, node)
|
||||
{
|
||||
if (entry->prepare != NULL)
|
||||
{
|
||||
entry->prepare();
|
||||
}
|
||||
}
|
||||
|
||||
nxmutex_unlock(&info->ta_lock);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: atfork_child
|
||||
*
|
||||
* Description:
|
||||
* Invoke this method in the child process after fork completes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void atfork_child(void)
|
||||
{
|
||||
FAR struct task_info_s *info = task_get_info();
|
||||
FAR struct list_node *list = &info->ta_atfork;
|
||||
FAR struct pthread_atfork_s *entry;
|
||||
|
||||
/* The parent handlers are called in the order of registration */
|
||||
|
||||
nxmutex_lock(&info->ta_lock);
|
||||
list_for_every_entry(list, entry,
|
||||
struct pthread_atfork_s, node)
|
||||
{
|
||||
if (entry->child != NULL)
|
||||
{
|
||||
entry->child();
|
||||
}
|
||||
}
|
||||
|
||||
nxmutex_unlock(&info->ta_lock);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: atfork_parent
|
||||
*
|
||||
* Description:
|
||||
* Invoke this method in the parent process after fork completes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void atfork_parent(void)
|
||||
{
|
||||
FAR struct task_info_s *info = task_get_info();
|
||||
FAR struct list_node *list = &info->ta_atfork;
|
||||
FAR struct pthread_atfork_s *entry;
|
||||
|
||||
/* The child handlers are called in the order of registration */
|
||||
|
||||
nxmutex_lock(&info->ta_lock);
|
||||
list_for_every_entry(list, entry,
|
||||
struct pthread_atfork_s, node)
|
||||
{
|
||||
if (entry->parent != NULL)
|
||||
{
|
||||
entry->parent();
|
||||
}
|
||||
}
|
||||
|
||||
nxmutex_unlock(&info->ta_lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -50,8 +148,23 @@
|
||||
pid_t fork(void)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
#ifdef CONFIG_PTHREAD_ATFORK
|
||||
atfork_prepare();
|
||||
#endif
|
||||
pid = up_fork();
|
||||
|
||||
#ifdef CONFIG_PTHREAD_ATFORK
|
||||
if (pid == 0)
|
||||
{
|
||||
atfork_child();
|
||||
}
|
||||
else
|
||||
{
|
||||
atfork_parent();
|
||||
}
|
||||
#endif
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,10 @@ int task_init_info(FAR struct task_group_s *group)
|
||||
nxmutex_init(&info->ta_lock);
|
||||
group->tg_info = info;
|
||||
|
||||
#ifdef CONFIG_PTHREAD_ATFORK
|
||||
list_initialize(&info->ta_atfork);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FILE_STREAM
|
||||
/* Initialize file streams for the task group */
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/mutex.h>
|
||||
#include <nuttx/lib/lib.h>
|
||||
#include <nuttx/list.h>
|
||||
|
||||
#include "tls.h"
|
||||
|
||||
@ -50,6 +51,21 @@ void task_uninit_info(FAR struct task_group_s *group)
|
||||
{
|
||||
FAR struct task_info_s *info = group->tg_info;
|
||||
|
||||
#ifdef CONFIG_PTHREAD_ATFORK
|
||||
/* Remove the functions that registered with pthread_atfork() */
|
||||
|
||||
FAR struct list_node *list = &info->ta_atfork;
|
||||
FAR struct pthread_atfork_s *entry;
|
||||
|
||||
while (!list_is_empty(list))
|
||||
{
|
||||
entry = list_first_entry(list,
|
||||
struct pthread_atfork_s, node);
|
||||
list_delete_init(&entry->node);
|
||||
lib_free(entry);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FILE_STREAM
|
||||
/* Free resource held by the stream list */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user