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* The per-process timers are not inherited.
21
22* The steps are:
23* -> Create a per-process timer
24* -> fork
25* -> check if the timer exists in child.
26
27* The test fails if the timer expires in child (timer signal is delivered).
28
29*/
30
31
32/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
33#define _POSIX_C_SOURCE 200112L
34
35/********************************************************************************************/
36/****************************** standard includes *****************************************/
37/********************************************************************************************/
38#include <pthread.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44
45#include <sys/wait.h>
46 #include <errno.h>
47
48#include <signal.h>
49 #include <time.h>
50
51/********************************************************************************************/
52/******************************   Test framework   *****************************************/
53/********************************************************************************************/
54#include "testfrmw.h"
55 #include "testfrmw.c"
56/* This header is responsible for defining the following macros:
57 * UNRESOLVED(ret, descr);
58 *    where descr is a description of the error and ret is an int (error code for example)
59 * FAILED(descr);
60 *    where descr is a short text saying why the test has failed.
61 * PASSED();
62 *    No parameter.
63 *
64 * Both three macros shall terminate the calling process.
65 * The testcase shall not terminate in any other maneer.
66 *
67 * The other file defines the functions
68 * void output_init()
69 * void output(char * string, ...)
70 *
71 * Those may be used to output information.
72 */
73
74/********************************************************************************************/
75/********************************** Configuration ******************************************/
76/********************************************************************************************/
77#ifndef VERBOSE
78#define VERBOSE 1
79#endif
80
81/********************************************************************************************/
82/***********************************    Test case   *****************************************/
83/********************************************************************************************/
84
85/* Global control value */
86int notified;
87
88/* Notification routine */
89void notification( union sigval sv )
90{
91	if ( sv.sival_int != SIGUSR1 )
92	{
93		output( "Got signal %d, expected %d\n", sv.sival_int, SIGUSR1 );
94		UNRESOLVED( 1, "Unexpected notification" );
95	}
96
97	notified = ( int ) getpid();
98}
99
100/* The main test function. */
101int main( int argc, char * argv[] )
102{
103	int ret, status;
104	pid_t child, ctl;
105
106	timer_t tmr;
107
108	struct sigevent se;
109
110	struct itimerspec it;
111
112	/* Initialize output */
113	output_init();
114
115	notified = 0;
116
117	/* Create the timer */
118	se.sigev_notify = SIGEV_THREAD;
119	se.sigev_signo = 0;
120	se.sigev_value.sival_int = SIGUSR1;
121	se.sigev_notify_function = &notification;
122	se.sigev_notify_attributes = NULL; /* default detached thread */
123
124	ret = timer_create( CLOCK_REALTIME, &se, &tmr );
125
126	if ( ret != 0 )
127	{
128		UNRESOLVED( errno, "Failed to create a timer" );
129	}
130
131	/* Arm the timer */
132	it.it_interval.tv_nsec = 0;
133
134	it.it_interval.tv_sec = 0;
135
136	it.it_value.tv_sec = 0;
137
138	it.it_value.tv_nsec = 500000000; /* 0.5 sec */
139
140	ret = timer_settime( tmr, 0, &it, NULL );
141
142	/* Create the child */
143	child = fork();
144
145	if ( child == ( pid_t ) - 1 )
146	{
147		UNRESOLVED( errno, "Failed to fork" );
148	}
149
150	/* child */
151	if ( child == ( pid_t ) 0 )
152	{
153
154		sleep( 1 );
155
156		if ( notified != 0 )
157		{
158			if ( notified == ( int ) getpid() )
159			{
160				FAILED( "Per-Process Timer was inherited in child" );
161			}
162			else
163			{
164				output( "Notification occured before the child forked" );
165			}
166		}
167
168		/* We're done */
169		exit( PTS_PASS );
170	}
171
172	/* Parent joins the child */
173	ctl = waitpid( child, &status, 0 );
174
175	if ( ctl != child )
176	{
177		UNRESOLVED( errno, "Waitpid returned the wrong PID" );
178	}
179
180	if ( ( !WIFEXITED( status ) ) || ( WEXITSTATUS( status ) != PTS_PASS ) )
181	{
182		FAILED( "Child exited abnormally" );
183	}
184
185	if ( notified != ( int ) getpid() )
186	{
187		output( "Notified value: %d\n", notified );
188		UNRESOLVED( -1, "No notification occured -- per process timers do not work?" );
189	}
190
191	/* Test passed */
192#if VERBOSE > 0
193	output( "Test passed\n" );
194
195#endif
196	PASSED;
197}
198
199