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