1/*
2* Copyright (c) 2005, Bull S.A..  All rights reserved.
3* Created by: Sebastien Decugis
4
5* This program is free software; you can redistribute it and/or modify it
6* under the terms of version 2 of the GNU General Public License as
7* published by the Free Software Foundation.
8*
9* This program is distributed in the hope that it would be useful, but
10* WITHOUT ANY WARRANTY; without even the implied warranty of
11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12*
13* You should have received a copy of the GNU General Public License along
14* with this program; if not, write the Free Software Foundation, Inc., 59
15* Temple Place - Suite 330, Boston MA 02111-1307, USA.
16
17
18* This sample test aims to check the following assertion:
19*
20* If there is not enough memory to store handler adresses,
21* the function returns ENOMEM.
22
23* The steps are:
24* -> Register up to 10000 handlers.
25* -> In case of failure, check the error code is ENOMEM.
26* -> Otherwise, check the handlers are all executed..
27
28*/
29
30
31/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
32#define _POSIX_C_SOURCE 200112L
33
34/******************************************************************************/
35/*************************** standard includes ********************************/
36/******************************************************************************/
37#include <pthread.h>
38#include <stdarg.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43
44#include <sys/wait.h>
45#include <errno.h>
46
47
48/******************************************************************************/
49/***************************   Test framework   *******************************/
50/******************************************************************************/
51#include "testfrmw.h"
52#include "testfrmw.c"
53/* This header is responsible for defining the following macros:
54 * UNRESOLVED(ret, descr);
55 *    where descr is a description of the error and ret is an int
56 *   (error code for example)
57 * FAILED(descr);
58 *    where descr is a short text saying why the test has failed.
59 * PASSED();
60 *    No parameter.
61 *
62 * Both three macros shall terminate the calling process.
63 * The testcase shall not terminate in any other maneer.
64 *
65 * The other file defines the functions
66 * void output_init()
67 * void output(char * string, ...)
68 *
69 * Those may be used to output information.
70 */
71
72/******************************************************************************/
73/**************************** Configuration ***********************************/
74/******************************************************************************/
75#ifndef VERBOSE
76#define VERBOSE 1
77#endif
78
79/******************************************************************************/
80/***************************    Test case   ***********************************/
81/******************************************************************************/
82
83pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
84
85int controls[ 3 ] = {0, 0, 0};
86/* pthread_atfork handlers */
87void prepare( void )
88{
89	controls[ 0 ] ++;
90}
91
92void parent( void )
93{
94	controls[ 1 ] ++;
95}
96
97void child( void )
98{
99	controls[ 2 ] ++;
100}
101
102
103/* Thread function */
104void * threaded( void * arg )
105{
106	int ret, status;
107	pid_t child, ctl;
108
109	/* Wait main thread has registered the handler */
110	ret = pthread_mutex_lock( &mtx );
111
112	if ( ret != 0 )
113	{
114		UNRESOLVED( ret, "Failed to lock mutex" );
115	}
116
117	ret = pthread_mutex_unlock( &mtx );
118
119	if ( ret != 0 )
120	{
121		UNRESOLVED( ret, "Failed to unlock mutex" );
122	}
123
124	/* fork */
125	child = fork();
126
127	if ( child == ( pid_t ) - 1 )
128	{
129		UNRESOLVED( errno, "Failed to fork" );
130	}
131
132	/* child */
133	if ( child == ( pid_t ) 0 )
134	{
135		if ( controls[ 0 ] != 10000 )
136		{
137			FAILED( "prepare handler skipped some rounds" );
138		}
139
140		if ( controls[ 2 ] != 10000 )
141		{
142			FAILED( "child handler skipped some rounds" );
143		}
144
145		/* We're done */
146		exit( PTS_PASS );
147	}
148
149	if ( controls[ 0 ] != 10000 )
150	{
151		FAILED( "prepare handler skipped some rounds" );
152	}
153
154	if ( controls[ 1 ] != 10000 )
155	{
156		FAILED( "parent handler skipped some rounds" );
157	}
158
159	/* Parent joins the child */
160	ctl = waitpid( child, &status, 0 );
161
162	if ( ctl != child )
163	{
164		UNRESOLVED( errno, "Waitpid returned the wrong PID" );
165	}
166
167	if ( ( !WIFEXITED( status ) ) || ( WEXITSTATUS( status ) != PTS_PASS ) )
168	{
169		FAILED( "Child exited abnormally" );
170	}
171
172
173	/* quit */
174	return NULL;
175}
176
177/* The main test function. */
178int main( int argc, char * argv[] )
179{
180	int ret, i;
181	pthread_t ch;
182
183	/* Initialize output */
184	output_init();
185
186	ret = pthread_mutex_lock( &mtx );
187
188	if ( ret != 0 )
189	{
190		UNRESOLVED( ret, "Failed to lock mutex" );
191	}
192
193	ret = pthread_create( &ch, NULL, threaded, NULL );
194
195	if ( ret != 0 )
196	{
197		UNRESOLVED( ret, "Failed to create a thread" );
198	}
199
200	/* Register the handlers */
201	for ( i = 0; i < 10000; i++ )
202	{
203		ret = pthread_atfork( prepare, parent, child );
204
205		if ( ret == ENOMEM )
206		{
207			output( "ENOMEM returned after %i iterations\n", i );
208			break;
209		}
210
211		if ( ret != 0 )
212		{
213			UNRESOLVED( ret, "Failed to register the atfork handlers" );
214		}
215	}
216
217	if ( ret == 0 )
218	{
219
220		/* Let the child go on */
221		ret = pthread_mutex_unlock( &mtx );
222
223		if ( ret != 0 )
224		{
225			UNRESOLVED( ret, "Failed to unlock mutex" );
226		}
227
228		ret = pthread_join( ch, NULL );
229
230		if ( ret != 0 )
231		{
232			UNRESOLVED( ret, "Failed to join the thread" );
233		}
234	}
235
236	/* Test passed */
237#if VERBOSE > 0
238
239	output( "Test passed\n" );
240
241#endif
242
243	PASSED;
244}
245
246
247