posixtestsuite: Fix permissions which got lost.
[dragonfly.git] / test / contrib / posixtestsuite-1.5.2 / conformance / interfaces / pthread_exit / 6-1.c
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 the calling thread is the last thread in the process,
21  * the effect are as if an implicit call to exit(0) had been made.
22
23  * The steps are:
24  *
25  * -> main creates a thread.
26  * -> this thread forks(). The new process contains only 1 thread.
27  * -> the thread in the new process calls pthread_exit(non-0 value).
28  * -> main process joins the child process and checks the behavior
29  *     is as if exit(0) had been called.
30  *     The checked items are:
31  *       -> the return value.
32  *       -> the atexit() routines have been called.
33   */
34
35
36  /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
37  #define _POSIX_C_SOURCE 200112L
38
39  /* Some routines are part of the XSI Extensions */
40 #ifndef WITHOUT_XOPEN
41  #define _XOPEN_SOURCE  600
42 #endif
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 <sched.h>
55  #include <semaphore.h>
56  #include <errno.h>
57  #include <assert.h>
58  #include <sys/wait.h>
59  #include <sys/mman.h>
60
61 /********************************************************************************************/
62 /******************************   Test framework   *****************************************/
63 /********************************************************************************************/
64  #include "testfrmw.h"
65  #include "testfrmw.c"
66  /* This header is responsible for defining the following macros:
67   * UNRESOLVED(ret, descr);
68   *    where descr is a description of the error and ret is an int (error code for example)
69   * FAILED(descr);
70   *    where descr is a short text saying why the test has failed.
71   * PASSED();
72   *    No parameter.
73   *
74   * Both three macros shall terminate the calling process.
75   * The testcase shall not terminate in any other maneer.
76   *
77   * The other file defines the functions
78   * void output_init()
79   * void output(char * string, ...)
80   *
81   * Those may be used to output information.
82   */
83
84 /********************************************************************************************/
85 /********************************** Configuration ******************************************/
86 /********************************************************************************************/
87 #ifndef VERBOSE
88 #define VERBOSE 1
89 #endif
90
91 /********************************************************************************************/
92 /***********************************    Test cases  *****************************************/
93 /********************************************************************************************/
94
95 #include "threads_scenarii.c"
96
97 /* This file will define the following objects:
98  * scenarii: array of struct __scenario type.
99  * NSCENAR : macro giving the total # of scenarii
100  * scenar_init(): function to call before use the scenarii array.
101  * scenar_fini(): function to call after end of use of the scenarii array.
102  */
103
104 /********************************************************************************************/
105 /***********************************    Real Test   *****************************************/
106 /********************************************************************************************/
107
108 /* This will be used to control that atexit() has been called */
109 int * ctl;
110 long mf;
111
112 void clnp(void)
113 {
114         *ctl = 1;
115 }
116
117 /* Thread routine */
118 void * threaded (void * arg)
119 {
120         int ret = 0;
121
122         pid_t pid, chk;
123         int status;
124
125         if (mf > 0)
126                 *ctl = 0;
127
128         pid = fork();
129         if (pid == (pid_t)-1)
130         {
131                 UNRESOLVED(errno, "Failed to fork()");
132         }
133         if (pid == 0)
134         {
135                 /* children */
136                 if (mf > 0)
137                 {
138                         ret = atexit(clnp);
139                         if (ret != 0)  {  UNRESOLVED(ret, "Failed to register atexit function");  }
140                 }
141
142                 /* exit the last (and only) thread */
143                 pthread_exit(&ret);
144
145                 FAILED("pthread_exit() did not terminate the process when there was only 1 thread");
146         }
147
148         /* Only the parent process goes this far */
149         chk = waitpid(pid, &status, 0);
150         if (chk != pid)
151         {
152                 output("Expected pid: %i. Got %i\n", (int)pid, (int)chk);
153                 UNRESOLVED(errno, "Waitpid failed");
154         }
155
156         if (WIFSIGNALED(status))
157         {
158                 output("Child process killed with signal %d\n",WTERMSIG(status));
159                 UNRESOLVED( -1 , "Child process was killed");
160         }
161
162         if (WIFEXITED(status))
163         {
164                 ret = WEXITSTATUS(status);
165         }
166         else
167         {
168                 UNRESOLVED( -1, "Child process was neither killed nor exited");
169         }
170
171         if (ret != 0)
172         {
173                 output("Exit status was: %i\n", ret);
174                 FAILED("The child process did not exit with 0 status.");
175         }
176
177         if (mf > 0)
178                 if (*ctl != 1)
179                         FAILED("pthread_exit() in the last thread did not execute atexit() routines");
180
181
182         /* Signal we're done (especially in case of a detached thread) */
183         do { ret = sem_post(&scenarii[sc].sem); }
184         while ((ret == -1) && (errno == EINTR));
185         if (ret == -1)  {  UNRESOLVED(errno, "Failed to wait for the semaphore");  }
186
187         return NULL;
188 }
189
190 /* Main routine */
191 int main (int argc, char *argv[])
192 {
193         int ret=0;
194         pthread_t child;
195
196         mf =sysconf(_SC_MAPPED_FILES);
197
198         output_init();
199
200         scenar_init();
201
202         /* We want to share some memory with the child process */
203         if (mf> 0)
204         {
205                 /* We will place the test data in a mmaped file */
206                 char filename[] = "/tmp/pthread_exit_6-1-XXXXXX";
207                 size_t sz;
208                 void * mmaped;
209                 int fd;
210                 char * tmp;
211
212                 /* We now create the temp files */
213                 fd = mkstemp(filename);
214                 if (fd == -1)
215                 { UNRESOLVED(errno, "Temporary file could not be created"); }
216
217                 /* and make sure the file will be deleted when closed */
218                 unlink(filename);
219
220                 #if VERBOSE > 1
221                 output("Temp file created (%s).\n", filename);
222                 #endif
223
224                 sz= (size_t)sysconf(_SC_PAGESIZE);
225
226                 tmp = calloc(1, sz);
227                 if (tmp == NULL)
228                 { UNRESOLVED(errno, "Memory allocation failed"); }
229
230                 /* Write the data to the file.  */
231                 if (write (fd, tmp, sz) != (ssize_t) sz)
232                 { UNRESOLVED(sz, "Writting to the file failed"); }
233
234                 free(tmp);
235
236                 /* Now we can map the file in memory */
237                 mmaped = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
238                 if (mmaped == MAP_FAILED)
239                 { UNRESOLVED(errno, "mmap failed"); }
240
241                 ctl = (int *) mmaped;
242
243                 /* Our datatest structure is now in shared memory */
244                 #if VERBOSE > 1
245                 output("Testdata allocated in shared memory.\n");
246                 #endif
247         }
248
249         for (sc=0; sc < NSCENAR; sc++)
250         {
251                 #if VERBOSE > 0
252                 output("-----\n");
253                 output("Starting test with scenario (%i): %s\n", sc, scenarii[sc].descr);
254                 #endif
255
256                 ret = pthread_create(&child, &scenarii[sc].ta, threaded, &ctl);
257                 switch (scenarii[sc].result)
258                 {
259                         case 0: /* Operation was expected to succeed */
260                                 if (ret != 0)  {  UNRESOLVED(ret, "Failed to create this thread");  }
261                                 break;
262
263                         case 1: /* Operation was expected to fail */
264                                 if (ret == 0)  {  UNRESOLVED(-1, "An error was expected but the thread creation succeeded");  }
265                                 break;
266
267                         case 2: /* We did not know the expected result */
268                         default:
269                                 #if VERBOSE > 0
270                                 if (ret == 0)
271                                         { output("Thread has been created successfully for this scenario\n"); }
272                                 else
273                                         { output("Thread creation failed with the error: %s\n", strerror(ret)); }
274                                 #endif
275                 }
276                 if (ret == 0) /* The new thread is running */
277                 {
278                         if (scenarii[sc].detached == 0)
279                         {
280                                 ret = pthread_join(child, NULL);
281                                 if (ret != 0)  {  UNRESOLVED(ret, "Unable to join a thread");  }
282                         }
283                         else
284                         {
285                                 /* Just wait for the thread to terminate */
286                                 do { ret = sem_wait(&scenarii[sc].sem); }
287                                 while ((ret == -1) && (errno == EINTR));
288                                 if (ret == -1)  {  UNRESOLVED(errno, "Failed to wait for the semaphore");  }
289                         }
290                 }
291         }
292
293         scenar_fini();
294         #if VERBOSE > 0
295         output("-----\n");
296         output("All test data destroyed\n");
297         output("Test PASSED\n");
298         #endif
299
300         PASSED;
301 }