1570af302Sopenharmony_ci// by Jens Gustedt from http://www.openwall.com/lists/musl/2014/08/11/1 2570af302Sopenharmony_ci// c11 threads test was removed and t_error messages were added 3570af302Sopenharmony_ci// the test deadlocks with a broken cond var implementation so 4570af302Sopenharmony_ci// cond_waits were changed to cond_timedwaits with short timeout 5570af302Sopenharmony_ci#include <stdio.h> 6570af302Sopenharmony_ci#include <string.h> 7570af302Sopenharmony_ci#include <time.h> 8570af302Sopenharmony_ci#include <stdlib.h> 9570af302Sopenharmony_ci#include <errno.h> 10570af302Sopenharmony_ci#include "test.h" 11570af302Sopenharmony_ci 12570af302Sopenharmony_ci# include <pthread.h> 13570af302Sopenharmony_ci 14570af302Sopenharmony_ci# define VERSION "POSIX threads" 15570af302Sopenharmony_ci 16570af302Sopenharmony_citypedef pthread_mutex_t mutex; 17570af302Sopenharmony_citypedef pthread_cond_t condition; 18570af302Sopenharmony_citypedef pthread_t thread; 19570af302Sopenharmony_citypedef void* thread_ret; 20570af302Sopenharmony_ci 21570af302Sopenharmony_ci# define mutex_init(M) pthread_mutex_init((M), 0) 22570af302Sopenharmony_ci# define mutex_destroy pthread_mutex_destroy 23570af302Sopenharmony_ci# define mutex_lock pthread_mutex_lock 24570af302Sopenharmony_ci# define mutex_unlock pthread_mutex_unlock 25570af302Sopenharmony_ci 26570af302Sopenharmony_ci# define condition_init(C) pthread_cond_init((C), 0) 27570af302Sopenharmony_ci# define condition_destroy pthread_cond_destroy 28570af302Sopenharmony_ci# define condition_wait pthread_cond_wait 29570af302Sopenharmony_ci# define condition_timedwait pthread_cond_timedwait 30570af302Sopenharmony_ci# define condition_signal pthread_cond_signal 31570af302Sopenharmony_ci# define condition_broadcast pthread_cond_broadcast 32570af302Sopenharmony_ci 33570af302Sopenharmony_ci 34570af302Sopenharmony_ci# define thread_create(ID, START, ARG) pthread_create(ID, 0, START, ARG) 35570af302Sopenharmony_ci# define thread_join pthread_join 36570af302Sopenharmony_ci 37570af302Sopenharmony_ci# define gettime(TS) clock_gettime(CLOCK_REALTIME, (TS)) 38570af302Sopenharmony_ci 39570af302Sopenharmony_ci# define errorstring strerror 40570af302Sopenharmony_ci 41570af302Sopenharmony_ci#ifdef __GLIBC__ 42570af302Sopenharmony_ci# define LIBRARY "glibc" 43570af302Sopenharmony_ci#else 44570af302Sopenharmony_ci# define LIBRARY "unidentified" 45570af302Sopenharmony_ci#endif 46570af302Sopenharmony_ci 47570af302Sopenharmony_ci#define trace2(L, ...) fprintf(stderr, __FILE__ ":" #L ": " __VA_ARGS__) 48570af302Sopenharmony_ci#define trace1(L, ...) trace2(L, __VA_ARGS__) 49570af302Sopenharmony_ci#ifdef DEBUG 50570af302Sopenharmony_ci# define trace(...) trace1(__LINE__, __VA_ARGS__) 51570af302Sopenharmony_ci#else 52570af302Sopenharmony_ci# define trace(...) do { if (0) trace1(__LINE__, __VA_ARGS__); } while (0) 53570af302Sopenharmony_ci#endif 54570af302Sopenharmony_ci 55570af302Sopenharmony_ci//#define tell(...) trace1(__LINE__, __VA_ARGS__) 56570af302Sopenharmony_ci#define tell(...) trace(__VA_ARGS__) 57570af302Sopenharmony_ci 58570af302Sopenharmony_cienum { 59570af302Sopenharmony_ci phases = 10, 60570af302Sopenharmony_ci threads = 10, 61570af302Sopenharmony_ci}; 62570af302Sopenharmony_ci 63570af302Sopenharmony_cistatic thread id[threads]; 64570af302Sopenharmony_cistatic unsigned args[threads]; 65570af302Sopenharmony_ci 66570af302Sopenharmony_cistatic mutex mut[phases]; 67570af302Sopenharmony_cistatic unsigned inside[phases]; 68570af302Sopenharmony_ci 69570af302Sopenharmony_cistatic condition cond_client; 70570af302Sopenharmony_cistatic condition cond_main; 71570af302Sopenharmony_cistatic unsigned volatile phase; 72570af302Sopenharmony_ci 73570af302Sopenharmony_cistatic void settimeout(struct timespec *ts) 74570af302Sopenharmony_ci{ 75570af302Sopenharmony_ci if (clock_gettime(CLOCK_REALTIME, ts)) 76570af302Sopenharmony_ci t_error("clock_gettime failed: %s\n", strerror(errno)); 77570af302Sopenharmony_ci ts->tv_nsec += 500*1000*1000; 78570af302Sopenharmony_ci if (ts->tv_nsec >= 1000*1000*1000) { 79570af302Sopenharmony_ci ts->tv_nsec -= 1000*1000*1000; 80570af302Sopenharmony_ci ts->tv_sec++; 81570af302Sopenharmony_ci } 82570af302Sopenharmony_ci} 83570af302Sopenharmony_ci 84570af302Sopenharmony_cistatic thread_ret client(void *arg) { 85570af302Sopenharmony_ci struct timespec ts; 86570af302Sopenharmony_ci unsigned * number = arg; 87570af302Sopenharmony_ci for (unsigned i = 0; i < phases; ++i) { 88570af302Sopenharmony_ci trace("thread %u in phase %u\n", *number, i); 89570af302Sopenharmony_ci mutex_lock(&mut[i]); 90570af302Sopenharmony_ci ++inside[i]; 91570af302Sopenharmony_ci if (inside[i] == threads) { 92570af302Sopenharmony_ci trace("thread %u is last, signalling main\n", *number); 93570af302Sopenharmony_ci int ret = condition_signal(&cond_main); 94570af302Sopenharmony_ci trace("thread %u is last, signalling main, %s\n", *number, errorstring(ret)); 95570af302Sopenharmony_ci if (ret) 96570af302Sopenharmony_ci t_error("thread %u is last in phase %u, signalling main failed: %s\n", *number, i, errorstring(ret)); 97570af302Sopenharmony_ci } 98570af302Sopenharmony_ci while (i == phase) { 99570af302Sopenharmony_ci tell("thread %u in phase %u (%u), waiting\n", *number, i, phase); 100570af302Sopenharmony_ci settimeout(&ts); 101570af302Sopenharmony_ci int ret = condition_timedwait(&cond_client, &mut[i], &ts); 102570af302Sopenharmony_ci trace("thread %u in phase %u (%u), finished, %s\n", *number, i, phase, errorstring(ret)); 103570af302Sopenharmony_ci if (ret) { 104570af302Sopenharmony_ci t_error("thread %u in phase %u (%u) finished waiting: %s\n", *number, i, phase, errorstring(ret)); 105570af302Sopenharmony_ci exit(t_status); 106570af302Sopenharmony_ci } 107570af302Sopenharmony_ci } 108570af302Sopenharmony_ci int ret = mutex_unlock(&mut[i]); 109570af302Sopenharmony_ci trace("thread %u in phase %u (%u), has unlocked mutex: %s\n", *number, i, phase, errorstring(ret)); 110570af302Sopenharmony_ci if (ret) 111570af302Sopenharmony_ci t_error("thread %u in phase %u (%u), failed to unlock: %s\n", *number, i, phase, errorstring(ret)); 112570af302Sopenharmony_ci } 113570af302Sopenharmony_ci return 0; 114570af302Sopenharmony_ci} 115570af302Sopenharmony_ci 116570af302Sopenharmony_ci 117570af302Sopenharmony_ciint main(void) { 118570af302Sopenharmony_ci struct timespec ts; 119570af302Sopenharmony_ci 120570af302Sopenharmony_ci tell("start up of main, using %s, library %s\n", VERSION, LIBRARY); 121570af302Sopenharmony_ci condition_init(&cond_client); 122570af302Sopenharmony_ci condition_init(&cond_main); 123570af302Sopenharmony_ci for (unsigned i = 0; i < phases; ++i) { 124570af302Sopenharmony_ci mutex_init(&mut[i]); 125570af302Sopenharmony_ci } 126570af302Sopenharmony_ci mutex_lock(&mut[0]); 127570af302Sopenharmony_ci 128570af302Sopenharmony_ci for (unsigned i = 0; i < threads; ++i) { 129570af302Sopenharmony_ci args[i] = i; 130570af302Sopenharmony_ci thread_create(&id[i], client, &args[i]); 131570af302Sopenharmony_ci } 132570af302Sopenharmony_ci 133570af302Sopenharmony_ci while (phase < phases) { 134570af302Sopenharmony_ci while (inside[phase] < threads) { 135570af302Sopenharmony_ci trace("main seeing %u threads in phase %u, waiting\n", inside[phase], phase); 136570af302Sopenharmony_ci settimeout(&ts); 137570af302Sopenharmony_ci int ret = condition_timedwait(&cond_main, &mut[phase], &ts); 138570af302Sopenharmony_ci tell("main seeing %u threads in phase %u, %s\n", inside[phase], phase, errorstring(ret)); 139570af302Sopenharmony_ci if (ret) { 140570af302Sopenharmony_ci t_error("main thread in phase %u (%u threads inside), finished waiting: %s\n", phase, inside[phase], errorstring(ret)); 141570af302Sopenharmony_ci return t_status; 142570af302Sopenharmony_ci } 143570af302Sopenharmony_ci } 144570af302Sopenharmony_ci /* now we know that everybody is waiting inside, lock the next 145570af302Sopenharmony_ci mutex, if any, such that nobody can enter the next phase 146570af302Sopenharmony_ci without our permission. */ 147570af302Sopenharmony_ci if (phase < phases-1) 148570af302Sopenharmony_ci mutex_lock(&mut[phase+1]); 149570af302Sopenharmony_ci /* Now signal all clients, update the phase count and release the 150570af302Sopenharmony_ci mutex they are waiting for. */ 151570af302Sopenharmony_ci int ret = condition_broadcast(&cond_client); 152570af302Sopenharmony_ci trace("main has broadcast to %u: %s\n", phase, errorstring(ret)); 153570af302Sopenharmony_ci if (ret) 154570af302Sopenharmony_ci t_error("main broadcast in phase %u failed: %s\n", phase, errorstring(ret)); 155570af302Sopenharmony_ci ++phase; 156570af302Sopenharmony_ci ret = mutex_unlock(&mut[phase-1]); 157570af302Sopenharmony_ci trace("main has unlocked mutex %u: %s\n", phase-1, errorstring(ret)); 158570af302Sopenharmony_ci if (ret) 159570af302Sopenharmony_ci t_error("main failed to unlock mutex %u: %s\n", phase-1, errorstring(ret)); 160570af302Sopenharmony_ci } 161570af302Sopenharmony_ci 162570af302Sopenharmony_ci 163570af302Sopenharmony_ci 164570af302Sopenharmony_ci trace("main finished loop\n"); 165570af302Sopenharmony_ci 166570af302Sopenharmony_ci for (unsigned i = 0; i < threads; ++i) { 167570af302Sopenharmony_ci trace("main joining thread %u\n", i); 168570af302Sopenharmony_ci int ret = thread_join(id[i], &(thread_ret){0}); 169570af302Sopenharmony_ci trace("main joining thread %u: %s\n", i, errorstring(ret)); 170570af302Sopenharmony_ci if (ret) 171570af302Sopenharmony_ci t_error("main failed join thread %u: %s\n", i, errorstring(ret)); 172570af302Sopenharmony_ci } 173570af302Sopenharmony_ci 174570af302Sopenharmony_ci /* C functions to destroy the control structures don't return error 175570af302Sopenharmony_ci information, so we can't check for errors, here. */ 176570af302Sopenharmony_ci for (unsigned i = 0; i < phases; ++i) { 177570af302Sopenharmony_ci mutex_destroy(&mut[i]); 178570af302Sopenharmony_ci } 179570af302Sopenharmony_ci condition_destroy(&cond_main); 180570af302Sopenharmony_ci condition_destroy(&cond_client); 181570af302Sopenharmony_ci 182570af302Sopenharmony_ci tell("shut down of main, using %s, library %s\n", VERSION, LIBRARY); 183570af302Sopenharmony_ci 184570af302Sopenharmony_ci return t_status; 185570af302Sopenharmony_ci} 186