1570af302Sopenharmony_ci// commit: fb11b6b85e1e01daf17228be32d7f98b47517363 2011-02-19
2570af302Sopenharmony_ci// pthread_exit should call dtors (even in the last thread)
3570af302Sopenharmony_ci#include <stdlib.h>
4570af302Sopenharmony_ci#include <string.h>
5570af302Sopenharmony_ci#include <errno.h>
6570af302Sopenharmony_ci#include <pthread.h>
7570af302Sopenharmony_ci#include <sys/wait.h>
8570af302Sopenharmony_ci#include <unistd.h>
9570af302Sopenharmony_ci#include "test.h"
10570af302Sopenharmony_ci
11570af302Sopenharmony_ci#define TEST(r, f) if (((r)=(f))) t_error(#f " failed: %s\n", strerror(r))
12570af302Sopenharmony_ci#define TESTC(c, m) ( (c) || (t_error("%s failed (" m ")\n", #c), 0) )
13570af302Sopenharmony_ci
14570af302Sopenharmony_cistatic pthread_key_t k;
15570af302Sopenharmony_cistatic int data;
16570af302Sopenharmony_ci
17570af302Sopenharmony_cistatic void dtor(void *p)
18570af302Sopenharmony_ci{
19570af302Sopenharmony_ci	*(int *)p = 1;
20570af302Sopenharmony_ci}
21570af302Sopenharmony_ci
22570af302Sopenharmony_cistatic void *start(void *arg)
23570af302Sopenharmony_ci{
24570af302Sopenharmony_ci	if (pthread_setspecific(k, arg))
25570af302Sopenharmony_ci		return arg;
26570af302Sopenharmony_ci	return 0;
27570af302Sopenharmony_ci}
28570af302Sopenharmony_ci
29570af302Sopenharmony_cistatic void cleanup(void)
30570af302Sopenharmony_ci{
31570af302Sopenharmony_ci	TESTC(data == 1, "dtor was not run for the last thread");
32570af302Sopenharmony_ci	_exit(t_status);
33570af302Sopenharmony_ci}
34570af302Sopenharmony_ci
35570af302Sopenharmony_cistatic void die(void)
36570af302Sopenharmony_ci{
37570af302Sopenharmony_ci	_exit(1);
38570af302Sopenharmony_ci}
39570af302Sopenharmony_ci
40570af302Sopenharmony_ciint main(void)
41570af302Sopenharmony_ci{
42570af302Sopenharmony_ci	pthread_t td;
43570af302Sopenharmony_ci	int r, arg=0, pid;
44570af302Sopenharmony_ci	void *res;
45570af302Sopenharmony_ci
46570af302Sopenharmony_ci	// test if atexit handlers are run after pthread_exit
47570af302Sopenharmony_ci	// (early musl failed this test)
48570af302Sopenharmony_ci	pid = fork();
49570af302Sopenharmony_ci	switch (pid) {
50570af302Sopenharmony_ci	case -1:
51570af302Sopenharmony_ci		t_error("fork failed: %s\n", strerror(errno));
52570af302Sopenharmony_ci		return 1;
53570af302Sopenharmony_ci	case 0:
54570af302Sopenharmony_ci		atexit(die);
55570af302Sopenharmony_ci		pthread_exit(0);
56570af302Sopenharmony_ci	default:
57570af302Sopenharmony_ci		if (waitpid(pid, &r, 0) != pid) {
58570af302Sopenharmony_ci			t_error("waitpid failed: %s\n", strerror(errno));
59570af302Sopenharmony_ci			return 1;
60570af302Sopenharmony_ci		}
61570af302Sopenharmony_ci		if (!WIFEXITED(r) || WEXITSTATUS(r) != 1) {
62570af302Sopenharmony_ci			t_error("atexit handler was not run after last thread exited"
63570af302Sopenharmony_ci				" (exited=%d, signal=%d, status=%d, want exit status=1)\n",
64570af302Sopenharmony_ci				WIFEXITED(r), !WIFEXITED(r)&&WIFSIGNALED(r)?WTERMSIG(r):0, WIFEXITED(r)?WEXITSTATUS(r):0);
65570af302Sopenharmony_ci			return 1;
66570af302Sopenharmony_ci		}
67570af302Sopenharmony_ci	}
68570af302Sopenharmony_ci
69570af302Sopenharmony_ci	// dtor should set tsd (arg and data) from 0 to 1
70570af302Sopenharmony_ci	if (atexit(cleanup)) {
71570af302Sopenharmony_ci		t_error("atexit failed\n");
72570af302Sopenharmony_ci		return 1;
73570af302Sopenharmony_ci	}
74570af302Sopenharmony_ci	TEST(r, pthread_key_create(&k, dtor));
75570af302Sopenharmony_ci	TEST(r, pthread_setspecific(k, &data));
76570af302Sopenharmony_ci	TEST(r, pthread_create(&td, 0, start, &arg));
77570af302Sopenharmony_ci	TEST(r, pthread_join(td, &res));
78570af302Sopenharmony_ci	TESTC(res == 0, "pthread_setspecific failed in thread");
79570af302Sopenharmony_ci	TESTC(arg == 1, "dtor failed to run");
80570af302Sopenharmony_ci	TESTC(data == 0, "tsd in main thread is corrupted");
81570af302Sopenharmony_ci	TESTC(pthread_getspecific(k) == &data, "tsd in main thread is corrupted");
82570af302Sopenharmony_ci	pthread_exit(0);
83570af302Sopenharmony_ci}
84