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 */