summaryrefslogtreecommitdiff
path: root/lib/libc_r/TEST/test_fork.c
blob: bf0cc583c802bb0c7abb8db59acc2cbab5a9a5a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* ==== test_fork.c ============================================================
 * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
 *
 * Description : Test fork() and dup2() calls.
 *
 *  1.00 94/04/29 proven
 *      -Started coding this file.
 */

#include <pthread.h>
#include <pthread_np.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include "test.h"

void *
sleeper(void *arg)
{

	pthread_set_name_np(pthread_self(), "slpr");
	sleep(10);
	PANIC("sleeper timed out");
}

static pid_t parent_pid;

static void
sigchld(sig)
	int sig;
{
	int status;

	/* we should have got a SIGCHLD */
	ASSERT(sig == SIGCHLD);
	/* We should be the parent */
	ASSERT(getpid() == parent_pid);
	/* wait for any child */
	CHECKe(wait(&status));
	/* the child should have called exit(0) */
	ASSERT(WIFEXITED(status));
	ASSERT(WEXITSTATUS(status) == 0);
	printf("parent ok\n");
	SUCCEED;
}

static int atfork_state = 0;

void
atfork_child2()
{
	ASSERT(atfork_state++ == 3);
	ASSERT(getpid() != parent_pid);
}

void
atfork_parent2()
{
	ASSERT(atfork_state++ == 3);
	ASSERT(getpid() == parent_pid);
}

void
atfork_prepare2()
{
	ASSERT(atfork_state++ == 0);
	ASSERT(getpid() == parent_pid);
}


void
atfork_child1()
{
	ASSERT(atfork_state++ == 2);
	ASSERT(getpid() != parent_pid);
}

void
atfork_parent1()
{
	ASSERT(atfork_state++ == 2);
	ASSERT(getpid() == parent_pid);
}

void
atfork_prepare1()
{
	ASSERT(atfork_state++ == 1);
	ASSERT(getpid() == parent_pid);
}

int
main()
{
	int flags;
	pid_t pid;
	pthread_t sleeper_thread;

	parent_pid = getpid();

	CHECKe(flags = fcntl(STDOUT_FILENO, F_GETFL));
	if ((flags & (O_NONBLOCK | O_NDELAY))) {
		CHECKe(fcntl(STDOUT_FILENO, F_SETFL, 
		    flags & ~(O_NONBLOCK | O_NDELAY)));
	}

	CHECKr(pthread_create(&sleeper_thread, NULL, sleeper, NULL));
	sleep(1);

	CHECKe(signal(SIGCHLD, sigchld));

	/* Install some atfork handlers */

	CHECKr(pthread_atfork(&atfork_prepare1, &atfork_parent1, 
		&atfork_child1));
	CHECKr(pthread_atfork(&atfork_prepare2, &atfork_parent2, 
		&atfork_child2));

	printf("forking\n");

	CHECKe(pid = fork());
	switch(pid) {
	case 0:
		/* child: */
		/* Our pid should change */
		ASSERT(getpid() != parent_pid);
		/* Our sleeper thread should have disappeared */
		ASSERT(ESRCH == pthread_cancel(sleeper_thread));
		/* The atfork handler should have run */
		ASSERT(atfork_state++ == 4);
		printf("child ok\n");
		_exit(0);
		PANIC("child _exit");
	default:
		/* parent: */
		/* Our pid should stay the same */
		ASSERT(getpid() == parent_pid);
		/* Our sleeper thread should still be around */
		CHECKr(pthread_cancel(sleeper_thread));
		/* The atfork handler should have run */
		ASSERT(atfork_state++ == 4);
		/* wait for the SIGCHLD from the child */
		CHECKe(pause());
		PANIC("pause");
	}
}