1 /* $OpenBSD: sem_timedwait.c,v 1.2 2014/01/22 04:31:45 guenther Exp $ */ 2 /* 3 * Martin Pieuchot <mpi@openbsd.org>, 2011. Public Domain. 4 */ 5 6 #include <err.h> 7 #include <errno.h> 8 #include <unistd.h> 9 #include <semaphore.h> 10 #include <signal.h> 11 #include <pthread.h> 12 #include "test.h" 13 14 15 void *waiter(void *arg); 16 17 void 18 handler(int sig) 19 { 20 static char message[] = "got sig\n"; 21 22 write(STDERR_FILENO, message, sizeof(message) - 1); 23 } 24 25 sem_t sem; 26 volatile int posted = 0, eintr_ok = 0; 27 28 int 29 main(int argc, char **argv) 30 { 31 pthread_t th; 32 struct sigaction sa; 33 struct timespec ts, ts2; 34 35 CHECKr(clock_gettime(CLOCK_REALTIME, &ts)); 36 ts.tv_sec += 3; 37 CHECKn(sem_timedwait(&sem, &ts)); 38 ASSERT(errno == EINVAL); 39 40 CHECKr(sem_init(&sem, 0, 0)); 41 42 CHECKr(pthread_create(&th, NULL, waiter, &sem)); 43 44 sleep(1); 45 46 printf("expect: sem_destroy on semaphore with waiters!\n"); 47 CHECKn(sem_destroy(&sem)); 48 ASSERT(errno == EBUSY); 49 50 posted = 1; 51 CHECKr(sem_post(&sem)); 52 CHECKr(pthread_join(th, NULL)); 53 54 /* test that sem_timedwait() resumes after handling a signal */ 55 memset(&sa, 0, sizeof sa); 56 sa.sa_handler = &handler; 57 sigemptyset(&sa.sa_mask); 58 sa.sa_flags = 0; 59 if (sigaction(SIGUSR1, &sa, NULL)) 60 err(1, "sigaction"); 61 posted = 0; 62 CHECKr(pthread_create(&th, NULL, waiter, &sem)); 63 sleep(1); 64 fprintf(stderr, "sending sig\n"); 65 eintr_ok = 1; 66 pthread_kill(th, SIGUSR1); 67 sleep(1); 68 fprintf(stderr, "posting\n"); 69 posted = 1; 70 eintr_ok = 0; 71 CHECKr(sem_post(&sem)); 72 CHECKr(pthread_join(th, NULL)); 73 74 CHECKr(clock_gettime(CLOCK_REALTIME, &ts)); 75 ts.tv_sec += 2; 76 CHECKn(sem_timedwait(&sem, &ts)); 77 ASSERT(errno == ETIMEDOUT); 78 CHECKr(clock_gettime(CLOCK_REALTIME, &ts2)); 79 if (timespeccmp(&ts, &ts2, < )) 80 timespecsub(&ts2, &ts, &ts); 81 else 82 timespecsub(&ts, &ts2, &ts); 83 CHECKr(clock_getres(CLOCK_REALTIME, &ts2)); 84 timespecadd(&ts2, &ts2, &ts2); /* 2 * resolution slop */ 85 ASSERT(timespeccmp(&ts, &ts2, < )); 86 87 CHECKe(sem_destroy(&sem)); 88 89 SUCCEED; 90 } 91 92 void * 93 waiter(void *arg) 94 { 95 sem_t *semp = arg; 96 struct timespec ts; 97 int value; 98 int r; 99 100 CHECKr(clock_gettime(CLOCK_REALTIME, &ts)); 101 ts.tv_sec += 3; 102 r = sem_timedwait(semp, &ts); 103 CHECKr(sem_getvalue(semp, &value)); 104 if (r == 0) { 105 ASSERT(value == 0); 106 ASSERT(posted != 0); 107 } else { 108 ASSERT(r == -1); 109 ASSERT(errno == EINTR); 110 ASSERT(eintr_ok); 111 if (posted) 112 ASSERT(value == 1); 113 else 114 ASSERT(value == 0); 115 } 116 117 return (NULL); 118 } 119