1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Tests for fork in multi-threaded environment.
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Copyright (C) 2000 Free Software Foundation, Inc.
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU C Library is free software; you can redistribute it and/or
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU Library General Public License as
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU C Library is distributed in the hope that it will be useful,
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   but WITHOUT ANY WARRANTY; without even the implied warranty of
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Library General Public License for more details.
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU Library General Public
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License along with the GNU C Library; see the file COPYING.LIB.  If not,
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Boston, MA 02111-1307, USA.  */
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <errno.h>
21b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#if !defined(__APPLE__)
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# include <error.h>
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdlib.h>
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <pthread.h>
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <unistd.h>
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <sys/wait.h>
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h>
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
30b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#if defined(__APPLE__)
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <string.h>  /* strerror */
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void error (int status, int errnum, char* msg)
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fprintf(stderr, "%s%s%s\n",
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           msg,
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           errnum ? ": " : "",
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           errnum ? strerror(errnum) : "");
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (errnum)
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      exit(errnum);
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownenum
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  PREPARE_BIT = 1,
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  PARENT_BIT = 2,
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  CHILD_BIT = 4
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown};
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int var;
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprepare (void)
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  var |= PREPARE_BIT;
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownparent (void)
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  var |= PARENT_BIT;
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownchild (void)
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  var |= CHILD_BIT;
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void *thread (void *arg);
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmain (void)
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_t th;
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  void *res;
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_atfork (prepare, parent, child);
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  if (pthread_create (&th, NULL, thread, NULL) != 0)
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    error (EXIT_FAILURE, 0, "cannot create thread");
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_join (th, &res);
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  if ( ( int ) ( long int ) res != 0 )
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      error(EXIT_FAILURE, 0, "pthread_join res != 0" );
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  printf ( "all ok\n" );
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return 0;
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void *
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownthread (void *arg)
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  int status;
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pid_t pid;
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pid = fork ();
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  if (pid == 0)
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    {
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We check whether the `prepare' and `child' function ran.  */
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      exit (var != (PREPARE_BIT | CHILD_BIT));
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  else if (pid == (pid_t) -1)
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    error (EXIT_FAILURE, errno, "cannot fork");
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  if (waitpid (pid, &status, 0) != pid)
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    error (EXIT_FAILURE, errno, "wrong child");
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  if (WTERMSIG (status) != 0)
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    error (EXIT_FAILURE, 0, "Child terminated incorrectly");
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  status = WEXITSTATUS (status);
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  if (status == 0)
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    status = var != (PREPARE_BIT | PARENT_BIT);
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return (void *) (long int) status;
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
122