1570af302Sopenharmony_ci#include <pthread.h> 2570af302Sopenharmony_ci#include <semaphore.h> 3570af302Sopenharmony_ci#include <string.h> 4570af302Sopenharmony_ci#include "test.h" 5570af302Sopenharmony_ci 6570af302Sopenharmony_ci#define TESTC(c, m) ( (c) || (t_error("%s failed (" m ")\n", #c), 0) ) 7570af302Sopenharmony_ci#define TESTR(r, f, m) ( \ 8570af302Sopenharmony_ci ((r) = (f)) == 0 || (t_error("%s failed: %s (" m ")\n", #f, strerror(r)), 0) ) 9570af302Sopenharmony_ci 10570af302Sopenharmony_cistatic void *start_async(void *arg) 11570af302Sopenharmony_ci{ 12570af302Sopenharmony_ci pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0); 13570af302Sopenharmony_ci sem_post(arg); 14570af302Sopenharmony_ci for (;;); 15570af302Sopenharmony_ci return 0; 16570af302Sopenharmony_ci} 17570af302Sopenharmony_ci 18570af302Sopenharmony_cistatic void cleanup1(void *arg) 19570af302Sopenharmony_ci{ 20570af302Sopenharmony_ci *(int *)arg = 1; 21570af302Sopenharmony_ci} 22570af302Sopenharmony_ci 23570af302Sopenharmony_cistatic void cleanup2(void *arg) 24570af302Sopenharmony_ci{ 25570af302Sopenharmony_ci *(int *)arg += 2; 26570af302Sopenharmony_ci} 27570af302Sopenharmony_ci 28570af302Sopenharmony_cistatic void cleanup3(void *arg) 29570af302Sopenharmony_ci{ 30570af302Sopenharmony_ci *(int *)arg += 3; 31570af302Sopenharmony_ci} 32570af302Sopenharmony_ci 33570af302Sopenharmony_cistatic void cleanup4(void *arg) 34570af302Sopenharmony_ci{ 35570af302Sopenharmony_ci *(int *)arg += 4; 36570af302Sopenharmony_ci} 37570af302Sopenharmony_ci 38570af302Sopenharmony_cistatic void *start_single(void *arg) 39570af302Sopenharmony_ci{ 40570af302Sopenharmony_ci pthread_cleanup_push(cleanup1, arg); 41570af302Sopenharmony_ci sleep(3); 42570af302Sopenharmony_ci pthread_cleanup_pop(0); 43570af302Sopenharmony_ci return 0; 44570af302Sopenharmony_ci} 45570af302Sopenharmony_ci 46570af302Sopenharmony_cistatic void *start_nested(void *arg) 47570af302Sopenharmony_ci{ 48570af302Sopenharmony_ci int *foo = arg; 49570af302Sopenharmony_ci pthread_cleanup_push(cleanup1, foo); 50570af302Sopenharmony_ci pthread_cleanup_push(cleanup2, foo+1); 51570af302Sopenharmony_ci pthread_cleanup_push(cleanup3, foo+2); 52570af302Sopenharmony_ci pthread_cleanup_push(cleanup4, foo+3); 53570af302Sopenharmony_ci sleep(3); 54570af302Sopenharmony_ci pthread_cleanup_pop(0); 55570af302Sopenharmony_ci pthread_cleanup_pop(0); 56570af302Sopenharmony_ci pthread_cleanup_pop(0); 57570af302Sopenharmony_ci pthread_cleanup_pop(0); 58570af302Sopenharmony_ci return 0; 59570af302Sopenharmony_ci} 60570af302Sopenharmony_ci 61570af302Sopenharmony_ciint main(void) 62570af302Sopenharmony_ci{ 63570af302Sopenharmony_ci pthread_t td; 64570af302Sopenharmony_ci sem_t sem1; 65570af302Sopenharmony_ci int r; 66570af302Sopenharmony_ci void *res; 67570af302Sopenharmony_ci int foo[4]; 68570af302Sopenharmony_ci 69570af302Sopenharmony_ci TESTR(r, sem_init(&sem1, 0, 0), "creating semaphore"); 70570af302Sopenharmony_ci 71570af302Sopenharmony_ci /* Asynchronous cancellation */ 72570af302Sopenharmony_ci TESTR(r, pthread_create(&td, 0, start_async, &sem1), "failed to create thread"); 73570af302Sopenharmony_ci while (sem_wait(&sem1)); 74570af302Sopenharmony_ci TESTR(r, pthread_cancel(td), "canceling"); 75570af302Sopenharmony_ci TESTR(r, pthread_join(td, &res), "joining canceled thread"); 76570af302Sopenharmony_ci TESTC(res == PTHREAD_CANCELED, "canceled thread exit status"); 77570af302Sopenharmony_ci 78570af302Sopenharmony_ci /* Cancellation cleanup handlers */ 79570af302Sopenharmony_ci foo[0] = 0; 80570af302Sopenharmony_ci TESTR(r, pthread_create(&td, 0, start_single, foo), "failed to create thread"); 81570af302Sopenharmony_ci TESTR(r, pthread_cancel(td), "cancelling"); 82570af302Sopenharmony_ci TESTR(r, pthread_join(td, &res), "joining canceled thread"); 83570af302Sopenharmony_ci TESTC(res == PTHREAD_CANCELED, "canceled thread exit status"); 84570af302Sopenharmony_ci TESTC(foo[0] == 1, "cleanup handler failed to run"); 85570af302Sopenharmony_ci 86570af302Sopenharmony_ci /* Nested cleanup handlers */ 87570af302Sopenharmony_ci memset(foo, 0, sizeof foo); 88570af302Sopenharmony_ci TESTR(r, pthread_create(&td, 0, start_nested, foo), "failed to create thread"); 89570af302Sopenharmony_ci TESTR(r, pthread_cancel(td), "cancelling"); 90570af302Sopenharmony_ci TESTR(r, pthread_join(td, &res), "joining canceled thread"); 91570af302Sopenharmony_ci TESTC(res == PTHREAD_CANCELED, "canceled thread exit status"); 92570af302Sopenharmony_ci TESTC(foo[0] == 1, "cleanup handler failed to run"); 93570af302Sopenharmony_ci TESTC(foo[1] == 2, "cleanup handler failed to run"); 94570af302Sopenharmony_ci TESTC(foo[2] == 3, "cleanup handler failed to run"); 95570af302Sopenharmony_ci TESTC(foo[3] == 4, "cleanup handler failed to run"); 96570af302Sopenharmony_ci 97570af302Sopenharmony_ci return t_status; 98570af302Sopenharmony_ci} 99