1*3f3c90a9SAndy Fiddaman /*
2*3f3c90a9SAndy Fiddaman  * This file and its contents are supplied under the terms of the
3*3f3c90a9SAndy Fiddaman  * Common Development and Distribution License ("CDDL"), version 1.0.
4*3f3c90a9SAndy Fiddaman  * You may only use this file in accordance with the terms of version
5*3f3c90a9SAndy Fiddaman  * 1.0 of the CDDL.
6*3f3c90a9SAndy Fiddaman  *
7*3f3c90a9SAndy Fiddaman  * A full copy of the text of the CDDL should have accompanied this
8*3f3c90a9SAndy Fiddaman  * source.  A copy of the CDDL is also available via the Internet at
9*3f3c90a9SAndy Fiddaman  * http://www.illumos.org/license/CDDL.
10*3f3c90a9SAndy Fiddaman  */
11*3f3c90a9SAndy Fiddaman 
12*3f3c90a9SAndy Fiddaman /*
13*3f3c90a9SAndy Fiddaman  * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
14*3f3c90a9SAndy Fiddaman  */
15*3f3c90a9SAndy Fiddaman 
16*3f3c90a9SAndy Fiddaman #include <atomic.h>
17*3f3c90a9SAndy Fiddaman #include <err.h>
18*3f3c90a9SAndy Fiddaman #include <pthread.h>
19*3f3c90a9SAndy Fiddaman #include <stdint.h>
20*3f3c90a9SAndy Fiddaman #include <stdio.h>
21*3f3c90a9SAndy Fiddaman #include <stdlib.h>
22*3f3c90a9SAndy Fiddaman #include <ucontext.h>
23*3f3c90a9SAndy Fiddaman #include <unistd.h>
24*3f3c90a9SAndy Fiddaman #include <sys/debug.h>
25*3f3c90a9SAndy Fiddaman #include <sys/types.h>
26*3f3c90a9SAndy Fiddaman 
27*3f3c90a9SAndy Fiddaman static __thread uint64_t tlsvar;
28*3f3c90a9SAndy Fiddaman static ucontext_t ctx;
29*3f3c90a9SAndy Fiddaman static uint32_t failures;
30*3f3c90a9SAndy Fiddaman static pthread_t tid;
31*3f3c90a9SAndy Fiddaman 
32*3f3c90a9SAndy Fiddaman #define	THREAD1_VALUE	0x1010
33*3f3c90a9SAndy Fiddaman #define	THREAD2_VALUE	0x0202
34*3f3c90a9SAndy Fiddaman 
35*3f3c90a9SAndy Fiddaman void
report(char * tag)36*3f3c90a9SAndy Fiddaman report(char *tag)
37*3f3c90a9SAndy Fiddaman {
38*3f3c90a9SAndy Fiddaman 	pthread_t ltid = pthread_self();
39*3f3c90a9SAndy Fiddaman 
40*3f3c90a9SAndy Fiddaman 	printf("  %-14s: thread=%x, TLS variable=%x\n",
41*3f3c90a9SAndy Fiddaman 	    tag, (uint_t)ltid, tlsvar);
42*3f3c90a9SAndy Fiddaman }
43*3f3c90a9SAndy Fiddaman 
44*3f3c90a9SAndy Fiddaman void
run(void)45*3f3c90a9SAndy Fiddaman run(void)
46*3f3c90a9SAndy Fiddaman {
47*3f3c90a9SAndy Fiddaman 	pthread_t ltid = pthread_self();
48*3f3c90a9SAndy Fiddaman 
49*3f3c90a9SAndy Fiddaman 	printf("Coroutine started from second thread\n");
50*3f3c90a9SAndy Fiddaman 	report("coroutine");
51*3f3c90a9SAndy Fiddaman 
52*3f3c90a9SAndy Fiddaman 	if (ltid != tid) {
53*3f3c90a9SAndy Fiddaman 		fprintf(stderr,
54*3f3c90a9SAndy Fiddaman 		    "FAIL: coroutine thread ID is %x, expected %x\n",
55*3f3c90a9SAndy Fiddaman 		    ltid, tid);
56*3f3c90a9SAndy Fiddaman 		atomic_inc_32(&failures);
57*3f3c90a9SAndy Fiddaman 	}
58*3f3c90a9SAndy Fiddaman 
59*3f3c90a9SAndy Fiddaman 	if (tlsvar != THREAD2_VALUE) {
60*3f3c90a9SAndy Fiddaman 		fprintf(stderr,
61*3f3c90a9SAndy Fiddaman 		    "FAIL: coroutine TLS variable is %x, expected %x\n",
62*3f3c90a9SAndy Fiddaman 		    tlsvar, THREAD2_VALUE);
63*3f3c90a9SAndy Fiddaman 		atomic_inc_32(&failures);
64*3f3c90a9SAndy Fiddaman 	}
65*3f3c90a9SAndy Fiddaman }
66*3f3c90a9SAndy Fiddaman 
67*3f3c90a9SAndy Fiddaman void *
thread(void * arg __unused)68*3f3c90a9SAndy Fiddaman thread(void *arg __unused)
69*3f3c90a9SAndy Fiddaman {
70*3f3c90a9SAndy Fiddaman 	tlsvar = THREAD2_VALUE;
71*3f3c90a9SAndy Fiddaman 
72*3f3c90a9SAndy Fiddaman 	report("second thread");
73*3f3c90a9SAndy Fiddaman 	/*
74*3f3c90a9SAndy Fiddaman 	 * setcontext() does not return if successful, checking the return
75*3f3c90a9SAndy Fiddaman 	 * value upsets smatch.
76*3f3c90a9SAndy Fiddaman 	 */
77*3f3c90a9SAndy Fiddaman 	(void) setcontext(&ctx);
78*3f3c90a9SAndy Fiddaman 	errx(EXIT_FAILURE, "setcontext() returned and should not have.");
79*3f3c90a9SAndy Fiddaman 
80*3f3c90a9SAndy Fiddaman 	return (NULL);
81*3f3c90a9SAndy Fiddaman }
82*3f3c90a9SAndy Fiddaman 
83*3f3c90a9SAndy Fiddaman int
main(void)84*3f3c90a9SAndy Fiddaman main(void)
85*3f3c90a9SAndy Fiddaman {
86*3f3c90a9SAndy Fiddaman 	char stk[SIGSTKSZ];
87*3f3c90a9SAndy Fiddaman 	void *status;
88*3f3c90a9SAndy Fiddaman 
89*3f3c90a9SAndy Fiddaman 	tlsvar = THREAD1_VALUE;
90*3f3c90a9SAndy Fiddaman 
91*3f3c90a9SAndy Fiddaman 	report("main thread");
92*3f3c90a9SAndy Fiddaman 
93*3f3c90a9SAndy Fiddaman 	VERIFY0(getcontext(&ctx));
94*3f3c90a9SAndy Fiddaman 	ctx.uc_link = NULL;
95*3f3c90a9SAndy Fiddaman 	ctx.uc_stack.ss_sp = stk;
96*3f3c90a9SAndy Fiddaman 	ctx.uc_stack.ss_size = sizeof (stk);
97*3f3c90a9SAndy Fiddaman 	makecontext(&ctx, run, 0);
98*3f3c90a9SAndy Fiddaman 
99*3f3c90a9SAndy Fiddaman 	VERIFY0(pthread_create(&tid, NULL, thread, NULL));
100*3f3c90a9SAndy Fiddaman 	VERIFY0(pthread_join(tid, &status));
101*3f3c90a9SAndy Fiddaman 
102*3f3c90a9SAndy Fiddaman 	return (failures == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
103*3f3c90a9SAndy Fiddaman }
104