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 assertions:
19*
20* If SA_RESTART is set in sa_flags, interruptible function interrupted by signal
21* shall restart silently.
22
23* The steps are:
24* -> create a child thread
25* -> child registers a handler for SIGPROF with SA_RESTART, then waits for the semaphore
26* -> parent kills the child with SIGPROF, then post the semaphore.
27
28* The test fails if the sem_wait function returns EINTR
29
30*Note:
31This test uses sem_wait to check if EINTR is returned. As the function is not required to
32fail with EINTR, the test may return PASS and the feature not be correct (false positive).
33Anyway, a false negative status cannot be returned.
34
35*/
36
37
38/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
39#define _POSIX_C_SOURCE 200112L
40
41/* This test tests for an XSI feature */
42#define _XOPEN_SOURCE 600
43
44/******************************************************************************/
45/*************************** standard includes ********************************/
46/******************************************************************************/
47#include <pthread.h>
48#include <stdarg.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
52#include <unistd.h>
53
54#include <semaphore.h>
55#include <signal.h>
56#include <errno.h>
57
58/******************************************************************************/
59/***************************   Test framework   *******************************/
60/******************************************************************************/
61#include "testfrmw.h"
62#include "testfrmw.c"
63/* This header is responsible for defining the following macros:
64 * UNRESOLVED(ret, descr);
65 *    where descr is a description of the error and ret is an int
66 *   (error code for example)
67 * FAILED(descr);
68 *    where descr is a short text saying why the test has failed.
69 * PASSED();
70 *    No parameter.
71 *
72 * Both three macros shall terminate the calling process.
73 * The testcase shall not terminate in any other maneer.
74 *
75 * The other file defines the functions
76 * void output_init()
77 * void output(char * string, ...)
78 *
79 * Those may be used to output information.
80 */
81
82/******************************************************************************/
83/**************************** Configuration ***********************************/
84/******************************************************************************/
85#ifndef VERBOSE
86#define VERBOSE 1
87#endif
88
89#define SIGNAL SIGPROF
90
91/******************************************************************************/
92/***************************    Test case   ***********************************/
93/******************************************************************************/
94
95volatile sig_atomic_t caught = 0;
96sem_t sem;
97
98/* Handler function */
99void handler( int signo )
100{
101	printf( "Caught signal %d\n", signo );
102	caught++;
103}
104
105/* Thread function */
106void * threaded ( void * arg )
107{
108	int ret = 0;
109
110	ret = sem_wait( &sem );
111
112	if ( ret != 0 )
113	{
114		if ( errno == EINTR )
115		{
116			FAILED( "The function returned EINTR while SA_RESTART is set" );
117		}
118		else
119		{
120			UNRESOLVED( errno, "sem_wait failed" );
121		}
122	}
123
124	return NULL;
125}
126
127/* main function */
128int main()
129{
130	int ret;
131	pthread_t child;
132
133
134	struct sigaction sa;
135
136	/* Initialize output */
137	output_init();
138
139	/* Set the signal handler */
140	sa.sa_flags = SA_RESTART;
141	sa.sa_handler = handler;
142	ret = sigemptyset( &sa.sa_mask );
143
144	if ( ret != 0 )
145	{
146		UNRESOLVED( ret, "Failed to empty signal set" );
147	}
148
149	/* Install the signal handler for SIGNAL */
150	ret = sigaction( SIGNAL, &sa, 0 );
151
152	if ( ret != 0 )
153	{
154		UNRESOLVED( ret, "Failed to set signal handler" );
155	}
156
157	/* Initialize the semaphore */
158	ret = sem_init( &sem, 0, 0 );
159
160	if ( ret != 0 )
161	{
162		UNRESOLVED( ret, "Failed to init a semaphore" );
163	}
164
165	/* Create the child thread */
166	ret = pthread_create( &child, NULL, threaded, NULL );
167
168	if ( ret != 0 )
169	{
170		UNRESOLVED( ret, "Failed to create a child thread" );
171	}
172
173	/* Let the child thread enter the wait routine...
174	  we use sched_yield as there is no certain way to test that the child
175	  is waiting for the semaphore... */
176	sched_yield();
177
178	sched_yield();
179
180	sched_yield();
181
182	/* Ok, now kill the child */
183	ret = pthread_kill( child, SIGNAL );
184
185	if ( ret != 0 )
186	{
187		UNRESOLVED( ret, "Failed to kill the child thread" );
188	}
189
190	/* wait that the child receives the signal */
191	while ( !caught )
192		sched_yield();
193
194	/* Now let the child run and terminate */
195	ret = sem_post( &sem );
196
197	if ( ret != 0 )
198	{
199		UNRESOLVED( errno, "Failed to post the semaphore" );
200	}
201
202	ret = pthread_join( child, NULL );
203
204	if ( ret != 0 )
205	{
206		UNRESOLVED( ret, "Failed to join the thread" );
207	}
208
209	/* terminate */
210	ret = sem_destroy( &sem );
211
212	if ( ret != 0 )
213	{
214		UNRESOLVED( ret, "Failed to destroy the semaphore" );
215	}
216
217
218	/* Test passed */
219#if VERBOSE > 0
220
221	output( "Test passed\n" );
222
223#endif
224
225	PASSED;
226}
227