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, \
|
&entry->member != (list); entry = temp, \
|
||||||
temp = container_of(temp->member.next, type, member))
|
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
|
* Public Type Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <nuttx/arch.h>
|
#include <nuttx/arch.h>
|
||||||
#include <nuttx/atexit.h>
|
#include <nuttx/atexit.h>
|
||||||
#include <nuttx/fs/fs.h>
|
#include <nuttx/fs/fs.h>
|
||||||
|
#include <nuttx/list.h>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
@ -125,6 +126,21 @@ struct getopt_s
|
|||||||
bool go_binitialized; /* true: getopt() has been initialized */
|
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
|
struct task_info_s
|
||||||
{
|
{
|
||||||
mutex_t ta_lock;
|
mutex_t ta_lock;
|
||||||
@ -149,6 +165,10 @@ struct task_info_s
|
|||||||
#ifdef CONFIG_FILE_STREAM
|
#ifdef CONFIG_FILE_STREAM
|
||||||
struct streamlist ta_streamlist; /* Holds C buffered I/O info */
|
struct streamlist ta_streamlist; /* Holds C buffered I/O info */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_PTHREAD_ATFORK
|
||||||
|
struct list_node ta_atfork; /* Holds the pthread_atfork_s list */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* struct pthread_cleanup_s *************************************************/
|
/* struct pthread_cleanup_s *************************************************/
|
||||||
|
@ -14,4 +14,10 @@ config PTHREAD_SPINLOCKS
|
|||||||
---help---
|
---help---
|
||||||
Enable support for pthread spinlocks.
|
Enable support for pthread spinlocks.
|
||||||
|
|
||||||
|
config PTHREAD_ATFORK
|
||||||
|
bool "pthread_atfork support"
|
||||||
|
default n
|
||||||
|
---help---
|
||||||
|
Enable support for pthread_atfork.
|
||||||
|
|
||||||
endmenu # pthread support
|
endmenu # pthread support
|
||||||
|
@ -22,21 +22,65 @@
|
|||||||
* Included Files
|
* Included Files
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/tls.h>
|
||||||
|
#include <nuttx/lib/lib.h>
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* 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),
|
int pthread_atfork(CODE void (*prepare)(void),
|
||||||
CODE void (*parent)(void),
|
CODE void (*parent)(void),
|
||||||
CODE void (*child)(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);
|
if (entry == NULL)
|
||||||
UNUSED(parent);
|
{
|
||||||
UNUSED(child);
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
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/config.h>
|
||||||
#include <nuttx/arch.h>
|
#include <nuttx/arch.h>
|
||||||
|
#include <nuttx/tls.h>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#if defined(CONFIG_ARCH_HAVE_FORK)
|
#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
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -50,8 +148,23 @@
|
|||||||
pid_t fork(void)
|
pid_t fork(void)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
|
#ifdef CONFIG_PTHREAD_ATFORK
|
||||||
|
atfork_prepare();
|
||||||
|
#endif
|
||||||
pid = up_fork();
|
pid = up_fork();
|
||||||
|
|
||||||
|
#ifdef CONFIG_PTHREAD_ATFORK
|
||||||
|
if (pid == 0)
|
||||||
|
{
|
||||||
|
atfork_child();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
atfork_parent();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +65,10 @@ int task_init_info(FAR struct task_group_s *group)
|
|||||||
nxmutex_init(&info->ta_lock);
|
nxmutex_init(&info->ta_lock);
|
||||||
group->tg_info = info;
|
group->tg_info = info;
|
||||||
|
|
||||||
|
#ifdef CONFIG_PTHREAD_ATFORK
|
||||||
|
list_initialize(&info->ta_atfork);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_FILE_STREAM
|
#ifdef CONFIG_FILE_STREAM
|
||||||
/* Initialize file streams for the task group */
|
/* Initialize file streams for the task group */
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <nuttx/kmalloc.h>
|
#include <nuttx/kmalloc.h>
|
||||||
#include <nuttx/mutex.h>
|
#include <nuttx/mutex.h>
|
||||||
#include <nuttx/lib/lib.h>
|
#include <nuttx/lib/lib.h>
|
||||||
|
#include <nuttx/list.h>
|
||||||
|
|
||||||
#include "tls.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;
|
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
|
#ifdef CONFIG_FILE_STREAM
|
||||||
/* Free resource held by the stream list */
|
/* Free resource held by the stream list */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user