Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 17 Mar 2000 19:29:32 +0100 (CET)
From:      mikko@dynas.se
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   bin/17437: pthread_atfork() missing from libc_r
Message-ID:  <200003171829.TAA17749@shiba.d.home.dynas.se>

next in thread | raw e-mail | index | archive | help

>Number:         17437
>Category:       bin
>Synopsis:       pthread_atfork() missing from libc_r
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Mar 17 10:30:02 PST 2000
>Closed-Date:
>Last-Modified:
>Originator:     Mikko Työläjärvi
>Release:        FreeBSD 5.0-CURRENT i386
>Organization:
>Environment:

FreeBSD [345].x

>Description:

While porting some code using pthreads to FreeBSD, I noticed to my
surprise that pthread_atfork() was nowhere to be found, and there
did not seem to be any PRs related to the function.

So either I am the only one using pthread_atfork(), or it has fallen
out of the standard...  Most other systems (Solaris, AIX, HP-UX, IRIX
and Linux) has the function, and it is documented at:

<http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_atfork.html>;

Enough complaining.  Unless I have seriously misunderstood the
workings of libc_r, the patch below should bring pthread_atfork() to
FreeBSD (applies against -CURRENT, March 16).  It works for me.

Someone may want to turn the man-page into proper English too...

	Regards,
	/Mikko


>How-To-Repeat:

Compile anything that uses pthread_atfork()...

>Fix:


--- lib/libc_r/uthread/Makefile.inc.org	Thu Mar 16 22:31:06 2000
+++ lib/libc_r/uthread/Makefile.inc	Thu Mar 16 22:31:42 2000
@@ -6,6 +6,7 @@
 SRCS+= \
 	uthread_accept.c \
 	uthread_aio_suspend.c \
+	uthread_atfork.c \
 	uthread_attr_destroy.c \
 	uthread_attr_init.c \
 	uthread_attr_getdetachstate.c \
--- lib/libc_r/man/pthread_atfork.3.orig	Fri Mar 17 19:01:53 2000
+++ lib/libc_r/man/pthread_atfork.3	Fri Mar 17 19:01:47 2000
@@ -0,0 +1,73 @@
+.\"
+.\" "THE BEER-WARE LICENSE" (Revision 42m):
+.\" <mikko@dynas.se> wrote this file.  As long as you retain this notice you
+.\" can do whatever you want with this stuff. If we meet some day, and you think
+.\" this stuff is worth it, you can buy me a beer in return.  Mikko Työläjärvi
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 16, 2000
+.Dt PTHREAD_ATFORK 3
+.Os BSD 4
+.Sh NAME
+.Nm pthread_atfork
+.Nd register fork handlers
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fn pthread_atfork "void (*prepare)(void)" "void (*parent)(void)" "void (*child)(void)"
+.Sh DESCRIPTION
+The
+.Fn pthread_atfork
+function registers fork handlers to be called before and after
+.Fn fork .
+Handlers are run in the context of the thread that calls
+.Fn fork .
+.Pp
+The
+.Fa prepare
+handlers are invoked before fork processing. The
+.Fa parent
+and
+.Fa child
+handlers are invoked after fork processing, in the parent and child
+processes respectively.
+Handlers will be called in the parent process even when the
+.Fn fork
+operation fails.
+.Pp
+Any number of handlers can be registered by
+.Fn pthread_atfork .
+Function pointers that are NULL will be ignored.
+The 
+.Fa Parent
+and
+.Fa child
+handlers are called in the order that they were registered. The
+.Fn prepare
+handlers are called in the reverse order.
+.Pp
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_atfork
+function will return zero.
+Otherwise an error number will be returned to
+indicate the error.
+.Sh ERRORS
+.Fn pthread_atfork
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+The process cannot allocate enough memory to register another set of
+handlers.
+.El
+.Pp
+.Sh SEE ALSO
+.Xr fork 2 ,
+.Xr atexit 3
+.Sh STANDARDS
+.Fn pthread_atfork
+conforms to ISO/IEC 9945-1 ANSI/IEEE
+.Pq Dq Tn POSIX
+.\" XXX: Dunno -- someone will have to check the exact details:
+Std 1003.1 Second Edition 1996-07-12.
--- lib/libc_r/man/Makefile.inc.org	Fri Mar 17 18:42:54 2000
+++ lib/libc_r/man/Makefile.inc	Fri Mar 17 18:42:31 2000
@@ -4,7 +4,8 @@
 
 .PATH: ${.CURDIR}/man
 
-MAN3+=	pthread_cancel.3 \
+MAN3+=	pthread_atfork.3 \
+	pthread_cancel.3 \
 	pthread_cleanup_pop.3 \
 	pthread_cleanup_push.3 \
 	pthread_cond_broadcast.3 \
--- include/pthread.h.org	Thu Mar 16 22:29:54 2000
+++ include/pthread.h	Thu Mar 16 22:37:37 2000
@@ -303,6 +303,9 @@
 
 int		pthread_attr_setfloatstate __P((pthread_attr_t *, int));
 int		pthread_attr_getfloatstate __P((pthread_attr_t *, int *));
+
+int		pthread_atfork __P((void (*prepare)(void),
+				    void (*parent)(void), void (*child)(void)));
 __END_DECLS
 
 #endif
--- lib/libc_r/uthread/pthread_private.h.org	Thu Mar 16 22:30:22 2000
+++ lib/libc_r/uthread/pthread_private.h	Fri Mar 17 16:26:21 2000
@@ -999,6 +999,16 @@
 #define _FD_UNLOCK(_fd,_type)		_thread_fd_unlock(_fd, _type)
 #endif
 
+/* Atfork handlers */
+#define ATFORK_PREPARE	0
+#define ATFORK_PARENT	1
+#define ATFORK_CHILD	2
+
+typedef struct atfork_data {
+	struct atfork_data *next, *prev;
+	void (*funcs[3])(void);
+} atfork_data;
+
 /*
  * Function prototype definitions.
  */
@@ -1060,6 +1070,7 @@
 void	_thread_enter_cancellation_point(void);
 void	_thread_leave_cancellation_point(void);
 void	_thread_cancellation_point(void);
+atfork_data *_thread_atfork_list(void);
 
 /* #include <signal.h> */
 int     _thread_sys_sigaction(int, const struct sigaction *, struct sigaction *);
--- lib/libc_r/uthread/uthread_atfork.c.org	Fri Mar 17 18:37:07 2000
+++ lib/libc_r/uthread/uthread_atfork.c	Fri Mar 17 18:27:19 2000
@@ -0,0 +1,56 @@
+/*
+ * "THE BEER-WARE LICENSE" (Revision 42m):
+ * <mikko@dynas.se> wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.  Mikko Työläjärvi
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#ifdef _THREAD_SAFE
+#include <pthread.h>
+#include "pthread_private.h"
+
+static atfork_data *atfork_list = NULL;
+static spinlock_t atfork_lock	= _SPINLOCK_INITIALIZER;
+
+int
+pthread_atfork(void (*prepare)(void),
+	       void (*parent)(void),
+	       void (*child)(void))
+{
+	atfork_data *ap;
+
+	if (prepare == NULL && parent == NULL && child == NULL)
+		return 0;
+
+	if ((ap = malloc(sizeof(atfork_data))) == NULL)
+		return ENOMEM;
+
+	ap->funcs[ATFORK_PREPARE] = prepare;
+	ap->funcs[ATFORK_PARENT] = parent;
+	ap->funcs[ATFORK_CHILD] = child;
+
+	_SPINLOCK(&atfork_lock);
+	if ((ap->next = atfork_list) != NULL)
+		atfork_list->prev = ap;
+	atfork_list = ap;
+	_SPINUNLOCK(&atfork_lock);
+
+	return 0;
+}
+
+atfork_data *
+_thread_atfork_list(void)
+{
+	atfork_data *ap;
+
+	_SPINLOCK(&atfork_lock);
+	ap = atfork_list;
+	_SPINUNLOCK(&atfork_lock);
+
+	return ap;
+}
+#endif
--- lib/libc_r/uthread/uthread_fork.c.org	Fri Mar 17 18:12:22 2000
+++ lib/libc_r/uthread/uthread_fork.c	Fri Mar 17 18:10:23 2000
@@ -47,6 +47,16 @@
 	pid_t		ret;
 	pthread_t	pthread;
 	pthread_t	pthread_save;
+	atfork_data	*ap, *alist;
+
+	/* Run any registered "prepare" callbacks: */
+	alist = _thread_atfork_list();
+	for (ap = alist; ap != NULL; ap = ap->next) {
+		if (ap->funcs[ATFORK_PREPARE] != NULL)
+			ap->funcs[ATFORK_PREPARE]();
+		if (ap->next == NULL)
+			break;
+	}
 
 	/*
 	 * Defer signals to protect the scheduling queues from access
@@ -216,6 +226,15 @@
 	 * Undefer and handle pending signals, yielding if necessary:
 	 */
 	_thread_kern_sig_undefer();
+
+	/*
+	 * Run any parent/child callbacks matching the "prepare" callbacks
+	 * from function entry, in reverse order:
+	 */
+	i = ret ? ATFORK_PARENT : ATFORK_CHILD;
+	for (; ap != NULL; ap = (ap != alist) ? ap->prev : NULL)
+		if (ap->funcs[i] != NULL)
+			ap->funcs[i]();
 
 	/* Return the process ID: */
 	return (ret);



>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200003171829.TAA17749>