You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by je...@apache.org on 2023/07/26 08:42:00 UTC
[nuttx] 02/02: libs/pthread/pthread_atfork: fulfill implement pthread_atfork function
This is an automated email from the ASF dual-hosted git repository.
jerpelea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 9d7f34966480543079c7268b2667a6647d42ae27
Author: guoshichao <gu...@xiaomi.com>
AuthorDate: Sat Jul 15 16:37:22 2023 +0800
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 <gu...@xiaomi.com>
---
include/nuttx/list.h | 9 +++
include/nuttx/tls.h | 20 +++++++
libs/libc/pthread/Kconfig | 6 ++
libs/libc/pthread/pthread_atfork.c | 54 ++++++++++++++++--
libs/libc/unistd/lib_fork.c | 113 +++++++++++++++++++++++++++++++++++++
sched/tls/task_initinfo.c | 4 ++
sched/tls/task_uninitinfo.c | 16 ++++++
7 files changed, 217 insertions(+), 5 deletions(-)
diff --git a/include/nuttx/list.h b/include/nuttx/list.h
index c71ad7f0bc..230acaff43 100644
--- a/include/nuttx/list.h
+++ b/include/nuttx/list.h
@@ -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
****************************************************************************/
diff --git a/include/nuttx/tls.h b/include/nuttx/tls.h
index 69b750885d..72fdf7e438 100644
--- a/include/nuttx/tls.h
+++ b/include/nuttx/tls.h
@@ -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 *************************************************/
diff --git a/libs/libc/pthread/Kconfig b/libs/libc/pthread/Kconfig
index 8e2c9f8804..19cbff73c9 100644
--- a/libs/libc/pthread/Kconfig
+++ b/libs/libc/pthread/Kconfig
@@ -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
diff --git a/libs/libc/pthread/pthread_atfork.c b/libs/libc/pthread/pthread_atfork.c
index 93d9d56dd3..80b0941041 100644
--- a/libs/libc/pthread/pthread_atfork.c
+++ b/libs/libc/pthread/pthread_atfork.c
@@ -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));
+
+ if (entry == NULL)
+ {
+ return ENOMEM;
+ }
+
+ list_initialize(&entry->node);
+ entry->prepare = prepare;
+ entry->parent = parent;
+ entry->child = child;
- UNUSED(prepare);
- UNUSED(parent);
- UNUSED(child);
+ nxmutex_lock(&info->ta_lock);
+ list_add_head(list, &entry->node);
+ nxmutex_unlock(&info->ta_lock);
+#endif
- return 0;
+ return OK;
}
diff --git a/libs/libc/unistd/lib_fork.c b/libs/libc/unistd/lib_fork.c
index e1a6463990..dbd3c1470d 100644
--- a/libs/libc/unistd/lib_fork.c
+++ b/libs/libc/unistd/lib_fork.c
@@ -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;
}
diff --git a/sched/tls/task_initinfo.c b/sched/tls/task_initinfo.c
index 88ded47c3d..a6d67e9183 100644
--- a/sched/tls/task_initinfo.c
+++ b/sched/tls/task_initinfo.c
@@ -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 */
diff --git a/sched/tls/task_uninitinfo.c b/sched/tls/task_uninitinfo.c
index 42bf6c23e7..3ccfee3f00 100644
--- a/sched/tls/task_uninitinfo.c
+++ b/sched/tls/task_uninitinfo.c
@@ -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 */