1/*
2 * Copyright (c) 2004, 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 attr is NULL, the effect is the same as passing the address
21 * of a default condition variable attributes object.
22
23 * The steps are:
24 * -> Create two cond vars, one with NULL attribute and
25 *    the other with a default attribute.
26 * -> Compare those two cond vars:
27 *    -> If the Thread Process-shared Synchronization is supported,
28 *       does both condvars have the same behavior across
29 *       different process? (Beware of the spurious wakeups).
30 *       (Steps to achieve this goal:
31 *          - Have the two cond vars created in shared memory.
32 *          - The associated mutex are process-shared and in shared memory also.
33 *          - Fork
34 *          - One thread in parent process and one thread in child process
35 *            wait for the cond.
36 *          - Broadcast the cond from the parent process;
37 *            then sleep for a while and check if the child process was awaken.
38 *          - Do the same with the other condvar; then compare the result.
39 *       )
40 */
41
42 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
43 #define _POSIX_C_SOURCE 200112L
44
45 /* We need the XSI extention for the mkstemp() routine
46  * - we could rewrite this test without this routine...
47  */
48#ifndef WITHOUT_XOPEN
49 #define _XOPEN_SOURCE	600
50#endif
51 /********************************************************************************************/
52/****************************** standard includes *****************************************/
53/********************************************************************************************/
54 #include <pthread.h>
55 #include <stdarg.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59
60 #include <errno.h>
61 #include <sys/wait.h>
62 #include <sys/mman.h>
63 #include <semaphore.h>
64 #include <string.h>
65 #include <signal.h>
66
67/********************************************************************************************/
68/******************************   Test framework   *****************************************/
69/********************************************************************************************/
70 #include "testfrmw.h"
71 #include "testfrmw.c"
72 /* This header is responsible for defining the following macros:
73  * UNRESOLVED(ret, descr);
74  *    where descr is a description of the error and ret is an int (error code for example)
75  * FAILED(descr);
76  *    where descr is a short text saying why the test has failed.
77  * PASSED();
78  *    No parameter.
79  *
80  * Both three macros shall terminate the calling process.
81  * The testcase shall not terminate in any other maneer.
82  *
83  * The other file defines the functions
84  * void output_init()
85  * void output(char * string, ...)
86  *
87  * Those may be used to output information.
88  */
89
90/********************************************************************************************/
91/********************************** Configuration ******************************************/
92/********************************************************************************************/
93#ifndef VERBOSE
94#define VERBOSE 1
95#endif
96
97/********************************************************************************************/
98/***********************************    Test case   *****************************************/
99/********************************************************************************************/
100#ifndef WITHOUT_XOPEN
101
102/* The data shared between both processes */
103typedef struct
104{
105	pthread_mutex_t mtxN; /* Mutex for Null attr condvar */
106	pthread_mutex_t mtxD; /* Mutex for Default attr condvar */
107	pthread_mutex_t mtxP; /* Mutex for Pshared condvar */
108	pthread_cond_t  cndN;
109	pthread_cond_t  cndD;
110	pthread_cond_t  cndP;
111	int cntrN;
112	int cntrD;
113	int cntrP;
114	char bool;
115	sem_t semA;
116	sem_t semB;
117	int result;
118	pid_t child;
119} globaldata_t;
120
121/* The data shared between the threads in the child process */
122typedef struct
123{
124	pthread_mutex_t * pmtx;
125	pthread_cond_t * pcnd;
126	int * pcntr;
127	char * pbool;
128	sem_t * psem;
129	pthread_t *pth;
130} datatest_t;
131
132/* The data shared with the signal handlers in the child process */
133struct
134{
135	sem_t * psem;
136	pthread_t th[3];
137} sigdata;
138
139/****
140 * The child threads signal handler.
141 *
142 */
143void childsighdl(int sig)
144{
145	int ret=0;
146	ret = sem_post(sigdata.psem);
147	if (ret != 0)
148	{  UNRESOLVED(errno, "[child] Unable to post semaphore in thread signal handler");  }
149}
150
151/****
152 * The child main signal handler
153 *
154 */
155void mainsighdl(int sig)
156{
157	/* We assume this signal handler is never called before the sigdata structure is initialized */
158	int ret = 0;
159
160	ret = pthread_kill(sigdata.th[0], SIGUSR2);
161	if (ret != 0)
162	{  UNRESOLVED(ret, "[child] Unable to kill a child thread");  }
163	ret = pthread_kill(sigdata.th[1], SIGUSR2);
164	if (ret != 0)
165	{  UNRESOLVED(ret, "[child] Unable to kill a child thread");  }
166	ret = pthread_kill(sigdata.th[2], SIGUSR2);
167	if (ret != 0)
168	{  UNRESOLVED(ret, "[child] Unable to kill a child thread");  }
169}
170
171/****
172 * child_process_th
173 *  Child process's thread function
174 *
175 */
176void * child_process_th(void * arg)
177{
178	int ret=0;
179	datatest_t * dt = (datatest_t *) arg;
180	struct sigaction sa;
181
182	/* Register into the signal data structure */
183	*(dt->pth) = pthread_self();
184
185	/* Set the signal action and mask for the child thread: Will call childsighdl when SIGUSR2 is received. */
186	sigemptyset (&sa.sa_mask);
187	sa.sa_flags = 0;
188	sa.sa_handler = childsighdl;
189	ret = sigaction (SIGUSR2, &sa, NULL);
190	if (ret != 0)
191	{  UNRESOLVED(ret, "[child] Unable to register action for SIGUSR2");  }
192
193	/* Any signal other than SIGUSR2 is blocked. */
194	sigfillset(&sa.sa_mask);
195	sigdelset(&sa.sa_mask, SIGUSR2);
196	ret = pthread_sigmask (SIG_SETMASK, &sa.sa_mask, NULL);
197	if (ret != 0)
198	{  UNRESOLVED(ret, "[child] Unable to set signal mask in child thread");  }
199
200
201	/* lock the mutex */
202	ret = pthread_mutex_lock(dt->pmtx);
203	if (ret != 0)
204	{  UNRESOLVED(ret, "[child][th] Unable to lock mutex.");  }
205
206	/* We can now let the parent thread start its work */
207	do { ret = sem_post(dt->psem); }
208	while ((ret != 0) && (errno == EINTR));
209	if (ret != 0)
210	{  UNRESOLVED(ret, "[child] Unable to post semaphore");  }
211
212	/* Now, do the actual test: wait for the cond */
213	do
214	{
215		*(dt->pcntr) += 1;
216		ret = pthread_cond_wait(dt->pcnd, dt->pmtx);
217		*(dt->pcntr) += 1;
218	} while ((ret == 0) && (*(dt->pbool) == 0));
219
220	if (ret != 0)
221	{
222		#if VERBOSE > 1
223		output("[child][thr] Unable to wait for the cond: %d - %s", ret, strerror(ret) );
224		#endif
225		*(dt->pcntr) = 0; /* this will signal the parent thread that an error happened */
226	}
227
228	/* unlock the mutex */
229	ret = pthread_mutex_unlock(dt->pmtx);
230	if (ret != 0)
231	{  UNRESOLVED(ret, "[child][th] Unable to unlock mutex.");  }
232
233	return NULL;
234}
235
236/****
237 * child_process
238 *  Child process main thread
239 *  This function is called in the child process just after the fork.
240 */
241int child_process(globaldata_t * gd)
242{
243	int ret;
244	datatest_t dtN, dtD, dtP;
245	pthread_t thN, thD, thP;
246
247	struct sigaction sa;
248
249	/* Initialize the datatest structures for the sub threads */
250	dtN.pmtx = &(gd->mtxN);
251	dtN.pcnd = &(gd->cndN);
252	dtN.pcntr = &(gd->cntrN);
253	dtN.pbool = &(gd->bool);
254	dtN.psem  = &(gd->semA);
255	dtN.pth = &(sigdata.th[0]);
256	dtD.pmtx = &(gd->mtxD);
257	dtD.pcnd = &(gd->cndD);
258	dtD.pcntr = &(gd->cntrD);
259	dtD.pbool = &(gd->bool);
260	dtD.psem  = &(gd->semA);
261	dtD.pth = &(sigdata.th[1]);
262	dtP.pmtx = &(gd->mtxP);
263	dtP.pcnd = &(gd->cndP);
264	dtP.pcntr = &(gd->cntrP);
265	dtP.pbool = &(gd->bool);
266	dtP.psem  = &(gd->semA);
267	dtP.pth = &(sigdata.th[2]);
268
269	sigdata.psem = &(gd->semA);
270
271	/* Register the signal handler: mainsighdl will be called when this thread receives SIGUSR1 */
272	sigemptyset (&sa.sa_mask);
273	sigaddset(&sa.sa_mask, SIGUSR2);
274	sa.sa_flags = 0;
275	sa.sa_handler = mainsighdl;
276	ret = sigaction (SIGUSR1, &sa, NULL);
277	if (ret != 0)
278	{  UNRESOLVED(ret, "[child] Unable to register action for SIGUSR1");  }
279
280	/* Set this thread's signal mask: we only accept SIGUSR1 */
281	sigfillset (&sa.sa_mask);
282	sigdelset(&sa.sa_mask, SIGUSR1);
283	ret = pthread_sigmask (SIG_SETMASK, &sa.sa_mask, NULL);
284	if (ret != 0)
285	{  UNRESOLVED(ret, "[child] Unable to set signal mask in child main thread");  }
286
287	/* We start the test threads */
288	ret = pthread_create(&thN, NULL, child_process_th, &dtN);
289	if (ret != 0)
290	{  UNRESOLVED(ret, "[child] Unable to create thread N");  }
291
292	ret = pthread_create(&thD, NULL, child_process_th, &dtD);
293	if (ret != 0)
294	{  UNRESOLVED(ret, "[child] Unable to create thread D");  }
295
296	ret = pthread_create(&thP, NULL, child_process_th, &dtP);
297	if (ret != 0)
298	{  UNRESOLVED(ret, "[child] Unable to create thread P");  }
299
300	/* We wait for the parent process to let us signal the conditions */
301	do { ret = sem_wait(&(gd->semB)); }
302	while ((ret != 0) && (errno == EINTR));
303	if (ret != 0)
304	{  UNRESOLVED(errno, "[child] Unable to wait for semaphore B");  }
305
306	/* Now signal both conditions. Changing the boolean was carried on by the parent */
307	ret = pthread_cond_signal(&(gd->cndN));
308	if (ret != 0)
309	{  UNRESOLVED(ret, "[child] Unable to signal cond N");  }
310
311	ret = pthread_cond_signal(&(gd->cndD));
312	if (ret != 0)
313	{  UNRESOLVED(ret, "[child] Unable to signal cond D");  }
314
315	ret = pthread_cond_signal(&(gd->cndP));
316	if (ret != 0)
317	{  UNRESOLVED(ret, "[child] Unable to signal cond P");  }
318
319	/* Nothing more to do until the threads terminate */
320	ret = pthread_join(thN, NULL);
321	if (ret != 0)
322	{  UNRESOLVED(ret, "[child] Unable to join the thread N");  }
323
324	ret = pthread_join(thD, NULL);
325	if (ret != 0)
326	{  UNRESOLVED(ret, "[child] Unable to join the thread D");  }
327
328	ret = pthread_join(thP, NULL);
329	if (ret != 0)
330	{  UNRESOLVED(ret, "[child] Unable to join the thread P");  }
331
332	return 0;
333}
334
335/****
336 * parent_process
337 *  This function is called in the parent process just after the fork.
338 *  Don't call the UNRESOLVED macro here as it would orphan the child thread!
339 *  Instead, the macro LOC_URSLVD(x, s) is provided. The usage is the same.
340 */
341#define LOC_URSLVD(x,s) \
342{ \
343	output("UNRESOLVED:\n Got error %d - %s\n with message %s\n", x, strerror(x), s);  \
344	gd->bool = 1; \
345	ret = sem_post(&(gd->semB)); \
346	if (ret != 0) \
347	{ \
348		kill(gd->child, SIGKILL); \
349		/* If the call fails, this probably means the process is already dead */ \
350	} \
351	return x; \
352}
353
354int parent_process(globaldata_t * gd)
355{
356	int ret, tmp, i;
357
358	/* Wait for the child to be ready */
359	ret = sem_wait(&(gd->semA));
360	if (ret != 0)
361	{  LOC_URSLVD(errno,"[parent] Unable to wait for sem A (1)");  }
362
363	ret = sem_wait(&(gd->semA));
364	if (ret != 0)
365	{  LOC_URSLVD(errno,"[parent] Unable to wait for sem A (2)");  }
366
367	ret = sem_wait(&(gd->semA));
368	if (ret != 0)
369	{  LOC_URSLVD(errno,"[parent] Unable to wait for sem A (3)");  }
370
371	#if VERBOSE > 1
372	output("[parent] Threads are ready...\n");
373	#endif
374
375	/* Now let the threads either enter the wait or exit if an error occured */
376	ret = pthread_mutex_lock(&(gd->mtxN));
377	if (ret != 0)
378	{  LOC_URSLVD(ret,"[parent] Unable to lock mutex N");  }
379
380	ret = pthread_mutex_lock(&(gd->mtxD));
381	if (ret != 0)
382	{  LOC_URSLVD(ret,"[parent] Unable to lock mutex D");  }
383
384	ret = pthread_mutex_lock(&(gd->mtxP));
385	if (ret != 0)
386	{  LOC_URSLVD(ret,"[parent] Unable to lock mutex P");  }
387
388	if (gd->cntrP == 0)
389	{
390		/* There was an unexpected error */
391		LOC_URSLVD(0,"[parent] The pshared condvar reported an error");
392	}
393	/* Check the threads status */
394	if ((gd->cntrN == 0) && (gd->cntrD == 0)) /* Both threads got an error */
395	{
396		/* the test has passed */
397		gd->result = 0;
398	}
399	if ((gd->cntrN == 0) && (gd->cntrD != 0)) /* thread N got an error */
400	{
401		/* the test has failed */
402		gd->result = gd->cntrD;
403	}
404	if ((gd->cntrN != 0) && (gd->cntrD == 0)) /* thread D got an error */
405	{
406		/* the test has failed */
407		gd->result = gd->cntrN;
408	}
409	if ((gd->cntrN != 0) && (gd->cntrD != 0)) /* Neither thread got an error - we can test further */
410	{
411		#if VERBOSE > 1
412		output("[parent] Both threads are waiting for the condition right now.\n");
413		#endif
414
415		/* We can unlock the mutexs so the threads can go out from pthread_cond_wait */
416		ret = pthread_mutex_unlock(&(gd->mtxN));
417		if (ret != 0)
418		{  LOC_URSLVD(ret,"[parent] Unable to unlock mutex N");  }
419
420		ret = pthread_mutex_unlock(&(gd->mtxD));
421		if (ret != 0)
422		{  LOC_URSLVD(ret,"[parent] Unable to unlock mutex D");  }
423
424		ret = pthread_mutex_unlock(&(gd->mtxP));
425		if (ret != 0)
426		{  LOC_URSLVD(ret,"[parent] Unable to unlock mutex P");  }
427
428		for (i=0; i<100; i++)
429		{
430			/* We try to signal the conditions */
431			tmp = pthread_cond_signal(&(gd->cndN));
432			ret = pthread_cond_signal(&(gd->cndD));
433			if (ret != tmp)
434			{  LOC_URSLVD(ret>tmp?ret:tmp, "[parent] Signaling the conditions give different error codes");  }
435			#if VERBOSE > 1
436			if (i==0)
437			{
438				output("[parent] Signaling the condition returned %d for both condvar\n", ret);
439			}
440			#endif
441			ret = pthread_cond_signal(&(gd->cndP));
442			if (ret != 0)
443			{  LOC_URSLVD(ret, "[parent] Signaling the pshared condition failed");  }
444
445
446			/* Make sure the child process's threads were scheduled */
447			/* We kill it and wait for both threads to have the signal handled.
448			  This will mean the threads were scheduled */
449			ret = kill(gd->child, SIGUSR1);
450			if (ret != 0)
451			{  LOC_URSLVD(errno, "[parent] Killing child thread with USR1 failed");  }
452
453			ret = sem_wait(&(gd->semA));
454			if (ret != 0)
455			{  LOC_URSLVD(errno,"[parent] Unable to wait for sem A (4)");  }
456
457			ret = sem_wait(&(gd->semA));
458			if (ret != 0)
459			{  LOC_URSLVD(errno,"[parent] Unable to wait for sem A (5)");  }
460
461			ret = sem_wait(&(gd->semA));
462			if (ret != 0)
463			{  LOC_URSLVD(errno,"[parent] Unable to wait for sem A (6)");  }
464
465			sched_yield();
466
467			/* We try to broadcast the conditions */
468			tmp = pthread_cond_broadcast(&(gd->cndN));
469			ret = pthread_cond_broadcast(&(gd->cndD));
470			if (ret != tmp)
471			{  LOC_URSLVD(ret>tmp?ret:tmp, "[parent] Broadcasting the conditions give different error codes");  }
472			#if VERBOSE > 1
473			if (i==0)
474			{
475				output("[parent] Broadcasting the condition returned %d for both condvar\n", tmp);
476			}
477			#endif
478			ret = pthread_cond_broadcast(&(gd->cndP));
479			if (ret != 0)
480			{  LOC_URSLVD(ret, "[parent] Broadcasting the pshared conditions failed");  }
481
482			/* Make sure the child process's threads were scheduled */
483			/* We kill it and wait for both threads to have the signal handled.
484			  This will mean the threads were scheduled */
485			ret = kill(gd->child, SIGUSR1);
486			if (ret != 0)
487			{  LOC_URSLVD(errno, "[parent] Killing child thread with USR1 failed");  }
488
489			ret = sem_wait(&(gd->semA));
490			if (ret != 0)
491			{  LOC_URSLVD(errno,"[parent] Unable to wait for sem A (7)");  }
492
493			ret = sem_wait(&(gd->semA));
494			if (ret != 0)
495			{  LOC_URSLVD(errno,"[parent] Unable to wait for sem A (8)");  }
496
497			ret = sem_wait(&(gd->semA));
498			if (ret != 0)
499			{  LOC_URSLVD(errno,"[parent] Unable to wait for sem A (9)");  }
500
501			sched_yield();
502		}
503
504
505		/* Now we relock the mutexes */
506		ret = pthread_mutex_lock(&(gd->mtxN));
507		if (ret != 0)
508		{  LOC_URSLVD(ret,"[parent] Unable to lock mutex N");  }
509
510		ret = pthread_mutex_lock(&(gd->mtxD));
511		if (ret != 0)
512		{  LOC_URSLVD(ret,"[parent] Unable to lock mutex D");  }
513
514		ret = pthread_mutex_lock(&(gd->mtxP));
515		if (ret != 0)
516		{  LOC_URSLVD(ret,"[parent] Unable to lock mutex P");  }
517
518		/* We compare the counters values */
519		if (gd->cntrP == 0)
520		{  LOC_URSLVD(0, "[parent] The pshared condvar failed");  }
521
522		if ((gd->cntrN == 0) && (gd->cntrD == 0))
523		{
524			#if VERBOSE > 1
525			output("[parent] Both cond wait have failed\n");
526			#endif
527			gd->result = 0; /* The test has passed */
528		}
529		if ((gd->cntrN == 0) && (gd->cntrD != 0))
530		{
531			#if VERBOSE > 1
532			output("[parent] cond wait has failed for N\n");
533			#endif
534			gd->result = gd->cntrD; /* The test has failed */
535		}
536		if ((gd->cntrN != 0) && (gd->cntrD == 0))
537		{
538			#if VERBOSE > 1
539			output("[parent] cond wait has failed for D\n");
540			#endif
541			gd->result = gd->cntrN; /* The test has failed */
542		}
543		if ((gd->cntrN != 0) && (gd->cntrD != 0)) /* None of the condwait returned an error */
544		{
545			if (((gd->cntrN & 1) != 1) || ((gd->cntrD & 1) != 1))
546			{
547				output("N:%d D:%d\n",gd->cntrN,gd->cntrD);
548				LOC_URSLVD((gd->cntrN & 1)?gd->cntrD:gd->cntrN,"[parent] Even counter - pshared mutex failure");
549			}
550
551			gd->result = 0;
552
553			#if VERBOSE > 1
554			output("[parent] Reports:\n");
555			output("[parent]  Process-shared condvar was awaken : %i times (reference)\n", gd->cntrP >> 1);
556			output("[parent]  Null attribute condvar was awaken : %i times\n", gd->cntrN >> 1);
557			output("[parent]  Default attr.  condvar was awaken : %i times\n", gd->cntrD >> 1);
558			#endif
559
560			if ((gd->cntrN == gd->cntrP) && (gd->cntrD != gd->cntrP))
561			{
562				#if VERBOSE > 1
563				output("[parent] Null condvar seems to be process-shared while Default condvar seems not\n");
564				#endif
565				gd->result = gd->cntrD;
566			}
567			if ((gd->cntrN != gd->cntrP) && (gd->cntrD == gd->cntrP))
568			{
569				#if VERBOSE > 1
570				output("[parent] Default condvar seems to be process-shared while Null condvar seems not\n");
571				#endif
572				gd->result = gd->cntrN;
573			}
574
575		}
576	}
577
578	#if VERBOSE > 1
579	output("[parent] Threads tests are finished, about to stop them...\n");
580	#endif
581	gd->bool = 1; /* the threads can now terminate */
582
583	ret = pthread_mutex_unlock(&(gd->mtxN));
584	if (ret != 0)
585	{  LOC_URSLVD(ret,"[parent] Unable to unlock mutex N");  }
586
587	ret = pthread_mutex_unlock(&(gd->mtxD));
588	if (ret != 0)
589	{  LOC_URSLVD(ret,"[parent] Unable to unlock mutex D");  }
590
591	ret = pthread_mutex_unlock(&(gd->mtxP));
592	if (ret != 0)
593	{  LOC_URSLVD(ret,"[parent] Unable to unlock mutex P");  }
594
595	/* Let the child thread terminate */
596	ret = sem_post(&(gd->semB));
597	if (ret != 0)
598	{  LOC_URSLVD(errno, "[parent] Failed to post the semaphore B");  }
599
600	return 0;
601}
602
603/****
604 * do_tps_test
605 *  This function will take care of testing the condvars
606 *  when shared between processes.
607 */
608int do_tps_test(void)
609{
610	int ret=0;
611	globaldata_t * gd;
612	pthread_condattr_t ca;
613	pthread_mutexattr_t ma;
614	pid_t wrc, child;
615
616	size_t sz;
617	char filename[] = "/tmp/cond_init_1-3-XXXXXX";
618	void * mmaped;
619	char * tmp;
620	int fd;
621
622	int status;
623	int rc2;
624
625
626	/* We now create the temp files */
627	fd = mkstemp(filename);
628	if (fd == -1)
629	{ UNRESOLVED(errno, "Temporary file could not be created"); }
630
631	/* and make sure the file will be deleted when closed */
632	unlink(filename);
633
634	#if VERBOSE > 1
635	output("Temp file created (%s).\n", filename);
636	#endif
637
638	sz= (size_t)sysconf(_SC_PAGESIZE);
639
640	tmp = calloc(1, sz);
641	if (tmp == NULL)
642	{ UNRESOLVED(errno, "Memory allocation failed"); }
643
644	/* Write the data to the file.  */
645	if (write (fd, tmp, sz) != (ssize_t) sz)
646	{ UNRESOLVED(sz, "Writting to the file failed"); }
647
648	free(tmp);
649
650	/* Now we can map the file in memory */
651	mmaped = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
652	if (mmaped == MAP_FAILED)
653	{ UNRESOLVED(errno, "mmap failed"); }
654
655	gd = (globaldata_t *) mmaped;
656
657	/* Our datatest structure is now in shared memory */
658	#if VERBOSE > 1
659	output("Shared memory created successfully.\n");
660	output("Initializing data...\n");
661	#endif
662
663	/* Initialize the objects attributes */
664	ret = pthread_mutexattr_init(&ma);
665	if (ret != 0)
666	{  UNRESOLVED(ret, "Unable to initialize mutex attribute object");  }
667
668	ret = pthread_condattr_init(&ca);
669	if (ret != 0)
670	{  UNRESOLVED(ret, "Unable to initialize condvar attribute object");  }
671
672	ret = pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED);
673	if (ret != 0)
674	{  UNRESOLVED(ret, "Unable to set the mutex attribute as process shared");  }
675
676	/* Initialize the synchronization objects */
677	ret = pthread_mutex_init(&(gd->mtxN), &ma);
678	if (ret != 0)
679	{  UNRESOLVED(ret, "Unable to initialize the mutex N in shared memory");  }
680
681	ret = pthread_mutex_init(&(gd->mtxD), &ma);
682	if (ret != 0)
683	{  UNRESOLVED(ret, "Unable to initialize the mutex D in shared memory");  }
684
685	ret = pthread_mutex_init(&(gd->mtxP), &ma);
686	if (ret != 0)
687	{  UNRESOLVED(ret, "Unable to initialize the mutex P in shared memory");  }
688
689	/* we don't need the mutex attribute object anymore */
690	ret = pthread_mutexattr_destroy(&ma);
691	if (ret != 0)
692	{  UNRESOLVED(ret, "Unable to destroy the mutex attribute object");  }
693
694	/* Now we'll initialize the cond vars */
695	ret = pthread_cond_init(&(gd->cndN), NULL);
696	if (ret != 0)
697	{  UNRESOLVED(ret, "Unable to initialize the Null attribute condvar");  }
698
699	ret = pthread_cond_init(&(gd->cndD), &ca);
700	if (ret != 0)
701	{  UNRESOLVED(ret, "Unable to initialize the Default attribute condvar");  }
702
703	ret = pthread_condattr_setpshared(&ca, PTHREAD_PROCESS_SHARED);
704	if (ret != 0)
705	{  UNRESOLVED(ret, "Unable to set the cond attribute as process shared");  }
706
707	ret = pthread_cond_init(&(gd->cndP), &ca);
708	if (ret != 0)
709	{  UNRESOLVED(ret, "Unable to initialize the Pshared condvar");  }
710
711	ret = pthread_condattr_destroy(&ca);
712	if (ret != 0)
713	{  UNRESOLVED(ret, "Unable to destroy the condvar attribute object");  }
714
715	/* We initialize the other values in the test structure */
716	gd->cntrN = 0;
717	gd->cntrD = 0;
718	gd->cntrP = 0;
719	gd->bool = 0;
720	gd->result = 0;
721	ret = sem_init(&(gd->semA), 1, 0);
722	if (ret != 0)
723	{  UNRESOLVED(errno, "Unable to initialize semaphore A");  }
724
725	ret = sem_init(&(gd->semB), 1, 0);
726	if (ret != 0)
727	{  UNRESOLVED(errno, "Unable to initialize semaphore B");  }
728
729	/* Initializations are OK */
730	#if VERBOSE > 1
731	output("All initializations OK, proceed to the test (fork).\n");
732	#endif
733
734	child = fork();
735	if (child == -1)
736	{  UNRESOLVED(errno, "Fork failed");  }
737
738	if (child == 0)
739	{
740		/* We are the child */
741		ret = child_process(gd);
742		#if VERBOSE > 1
743		output("[child] Test function returned %d.\n", ret);
744		#endif
745		exit(ret);
746	}
747
748	/* We are the parent */
749	gd->child = child;
750	rc2 = parent_process(gd);
751	#if VERBOSE > 1
752	output("[parent] Test function returned %d.\n", rc2);
753	#endif
754
755	/* In any case we must wait for the child */
756	wrc = waitpid(child, &status, 0);
757	if (wrc != child)
758	{
759		output("Expected pid: %i. Got %i\n", (int)child, (int)wrc);
760		UNRESOLVED(errno, "Waitpid failed");
761	}
762
763	if (WIFSIGNALED(status))
764	{
765		output("Child process killed with signal %d\n",WTERMSIG(status));
766		UNRESOLVED( rc2 , "Child process was killed");
767	}
768
769	if (WIFEXITED(status))
770	{
771		ret = WEXITSTATUS(status);
772	}
773	else
774	{
775		UNRESOLVED( rc2, "Child process was neither killed nor exited");
776	}
777
778	#if VERBOSE > 1
779	output("[parent] Successfully waited for child process.\n");
780	#endif
781
782	/* The return value from the parent is in 'rc2' and
783	 * 'ret' contains the child return code.
784	 * The test status is in gd->result
785	 */
786	if (rc2 != 0)
787	{
788		UNRESOLVED(ret, "Parent process failed");
789	}
790
791	if (ret != 0)
792	{
793		UNRESOLVED(ret, "Child process failed");
794	}
795
796	#if VERBOSE > 1
797	output("Destroying the data.\n");
798	#endif
799
800	/* We can now destroy all the datas */
801	ret = sem_destroy(&(gd->semB));
802	if (ret != 0)
803	{  UNRESOLVED(errno, "Unable to destroy the semaphore B");  }
804
805	ret = sem_destroy(&(gd->semA));
806	if (ret != 0)
807	{  UNRESOLVED(errno, "Unable to destroy the semaphore A");  }
808
809	ret = pthread_cond_destroy(&(gd->cndP));
810	if (ret != 0)
811	{  UNRESOLVED(ret, "Unable to destroy the P condvar");  }
812
813	ret = pthread_cond_destroy(&(gd->cndD));
814	if (ret != 0)
815	{  UNRESOLVED(ret, "Unable to destroy the D condvar");  }
816
817	ret = pthread_cond_destroy(&(gd->cndN));
818	if (ret != 0)
819	{  UNRESOLVED(ret, "Unable to destroy the N condvar");  }
820
821	ret = pthread_mutex_destroy(&(gd->mtxP));
822	if (ret != 0)
823	{  UNRESOLVED(ret, "Unable to destroy the P mutex");  }
824
825	ret = pthread_mutex_destroy(&(gd->mtxD));
826	if (ret != 0)
827	{  UNRESOLVED(ret, "Unable to destroy the D mutex");  }
828
829	ret = pthread_mutex_destroy(&(gd->mtxN));
830	if (ret != 0)
831	{  UNRESOLVED(ret, "Unable to destroy the N mutex");  }
832
833	rc2 = gd->result;
834
835	#if VERBOSE > 1
836	output("Unmapping shared memory.\n");
837	#endif
838
839	ret = munmap(mmaped, sz);
840	if (ret != 0)
841	{  UNRESOLVED(errno, "Memory unmapping failed");  }
842
843	return rc2;
844}
845
846/****
847 * Main function
848 *  This one is responsible for executing the previous functions
849 *  according to the supported features.
850 */
851int main(int argc, char * argv[])
852{
853	long opt_TPS, opt_MF;
854	int ret=0;
855
856	output_init();
857
858	#if VERBOSE > 1
859	output("Test starting...\n");
860	#endif
861
862	opt_MF =sysconf(_SC_MAPPED_FILES);
863	opt_TPS=sysconf(_SC_THREAD_PROCESS_SHARED);
864
865	#if VERBOSE > 1
866	output("Memory Mapped Files option : %li\n", opt_MF);
867	output("Thread Process-shared Synchronization option: %li\n", opt_TPS);
868	#endif
869
870	if ((opt_TPS != -1L) && (opt_MF != -1L))
871	{
872		#if VERBOSE > 0
873		output("Starting process test\n");
874		#endif
875		ret = do_tps_test();
876	}
877	else
878	{
879		UNTESTED("This test requires unsupported features");
880	}
881
882	if (ret != 0)
883	{  FAILED("The cond vars behave differently across processes.");  }
884
885	#if VERBOSE > 1
886	output("Test terminated successfully\n");
887	#endif
888
889	PASSED;
890}
891
892#else /* WITHOUT_XOPEN */
893int main(int argc, char * argv[])
894{
895	output_init();
896	UNTESTED("This test requires XSI features");
897}
898#endif
899
900