cancellation-points.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. * Make sure functions marked as cancellation points actually are.
  3. * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html#tag_02_09_05
  4. */
  5. #ifndef _GNU_SOURCE
  6. #define _GNU_SOURCE
  7. #endif
  8. #include <features.h>
  9. #include <sys/ipc.h>
  10. #include <sys/mman.h>
  11. #include <sys/msg.h>
  12. #include <sys/socket.h>
  13. #include <sys/types.h>
  14. #include <sys/wait.h>
  15. #include <fcntl.h>
  16. #include <mqueue.h>
  17. #include <poll.h>
  18. #include <pthread.h>
  19. #include <semaphore.h>
  20. #include <signal.h>
  21. #include <stdbool.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <termios.h>
  25. #include <time.h>
  26. #include <unistd.h>
  27. /* take care of optional things ... */
  28. #define STUB(func, args) static void func args { sleep(0); }
  29. #if !defined(__UCLIBC__) || defined(__UCLIBC_AIO__)
  30. # include <aio.h>
  31. #else
  32. STUB(aio_suspend, (void *p, int n, const void *p2))
  33. #endif
  34. #if !defined(__UCLIBC__) || defined(__UCLIBC_STROPTS__)
  35. # include <stropts.h>
  36. #else
  37. STUB(getmsg, (int f, void *p, void *p2, void *p3))
  38. STUB(getpmsg, (int f, void *p, void *p2, void *p3, void *p4))
  39. STUB(putmsg, (int f, void *p, void *p2, void *p3))
  40. STUB(putpmsg, (int f, void *p, void *p2, void *p3, void *p4))
  41. #endif
  42. #if defined(__UCLIBC__)
  43. STUB(clock_nanosleep, (int i, int f, const void *p, void *p2))
  44. #endif
  45. int cnt;
  46. bool ready;
  47. void cancel_timeout(int sig)
  48. {
  49. ready = false;
  50. }
  51. void cancel_thread_cleanup(void *arg)
  52. {
  53. ready = false;
  54. }
  55. /* some funcs need some help as they wont take NULL args ... */
  56. const struct timespec zero_sec = { .tv_sec = 0, .tv_nsec = 0 };
  57. sem_t sem;
  58. void help_sem_setup(void)
  59. {
  60. if (sem_init(&sem, 0, 1) == -1) {
  61. perror("sem_init() failed");
  62. exit(-1);
  63. }
  64. }
  65. pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  66. pthread_mutex_t mutex;
  67. void help_pthread_setup(void)
  68. {
  69. pthread_mutex_init(&mutex, NULL);
  70. pthread_mutex_lock(&mutex);
  71. }
  72. /* the pthread function that will call the cancellable function over and over */
  73. #define _MAKE_CANCEL_THREAD_FUNC_EX(func, sysfunc, args, setup) \
  74. void *cancel_thread_##func(void *arg) \
  75. { \
  76. if (pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL)) { \
  77. perror("unable to set cancel type to deferred; something is seriously broken"); \
  78. exit(-1); \
  79. } \
  80. pthread_cleanup_push(cancel_thread_cleanup, NULL); \
  81. setup; \
  82. ready = true; \
  83. while (ready) \
  84. sysfunc args; \
  85. pthread_cleanup_pop(1); \
  86. return NULL; \
  87. }
  88. #define MAKE_CANCEL_THREAD_FUNC_RE(func, sysfunc, args) _MAKE_CANCEL_THREAD_FUNC_EX(func, sysfunc, args, (void)0)
  89. #define MAKE_CANCEL_THREAD_FUNC_EX(func, args, setup) _MAKE_CANCEL_THREAD_FUNC_EX(func, func, args, setup)
  90. #define MAKE_CANCEL_THREAD_FUNC(func, args) _MAKE_CANCEL_THREAD_FUNC_EX(func, func, args, (void)0)
  91. MAKE_CANCEL_THREAD_FUNC(accept, (-1, NULL, NULL))
  92. MAKE_CANCEL_THREAD_FUNC(aio_suspend, (NULL, 0, &zero_sec))
  93. MAKE_CANCEL_THREAD_FUNC(clock_nanosleep, (0, 0, NULL, NULL))
  94. MAKE_CANCEL_THREAD_FUNC(close, (-1))
  95. MAKE_CANCEL_THREAD_FUNC(connect, (-1, NULL, 0))
  96. MAKE_CANCEL_THREAD_FUNC(creat, ("", 0))
  97. MAKE_CANCEL_THREAD_FUNC(fcntl, (0, F_SETLKW, NULL))
  98. MAKE_CANCEL_THREAD_FUNC(fdatasync, (-1))
  99. MAKE_CANCEL_THREAD_FUNC(fsync, (0))
  100. MAKE_CANCEL_THREAD_FUNC(getmsg, (-1, NULL, NULL, NULL))
  101. MAKE_CANCEL_THREAD_FUNC(getpmsg, (-1, NULL, NULL, NULL, NULL))
  102. MAKE_CANCEL_THREAD_FUNC(lockf, (-1, F_TEST, 0))
  103. MAKE_CANCEL_THREAD_FUNC(mq_receive, (0, NULL, 0, NULL))
  104. MAKE_CANCEL_THREAD_FUNC(mq_send, (0, NULL, 0, 0))
  105. MAKE_CANCEL_THREAD_FUNC(mq_timedreceive, (0, NULL, 0, NULL, NULL))
  106. MAKE_CANCEL_THREAD_FUNC(mq_timedsend, (0, NULL, 0, 0, NULL))
  107. MAKE_CANCEL_THREAD_FUNC(msgrcv, (-1, NULL, 0, 0, 0))
  108. MAKE_CANCEL_THREAD_FUNC(msgsnd, (-1, NULL, 0, 0))
  109. MAKE_CANCEL_THREAD_FUNC(msync, (NULL, 0, 0))
  110. MAKE_CANCEL_THREAD_FUNC(nanosleep, (NULL, NULL))
  111. MAKE_CANCEL_THREAD_FUNC(open, ("", 0))
  112. MAKE_CANCEL_THREAD_FUNC(pause, ())
  113. MAKE_CANCEL_THREAD_FUNC(poll, (NULL, 0, 0))
  114. MAKE_CANCEL_THREAD_FUNC(pread, (-1, NULL, 0, 0))
  115. MAKE_CANCEL_THREAD_FUNC(pselect, (0, NULL, NULL, NULL, NULL, NULL))
  116. MAKE_CANCEL_THREAD_FUNC_EX(pthread_cond_timedwait, (&cond, &mutex, &zero_sec), help_pthread_setup())
  117. MAKE_CANCEL_THREAD_FUNC_EX(pthread_cond_wait, (&cond, &mutex), help_pthread_setup())
  118. /*MAKE_CANCEL_THREAD_FUNC_EX(pthread_join, (0, NULL))*/
  119. MAKE_CANCEL_THREAD_FUNC(pthread_testcancel, ())
  120. MAKE_CANCEL_THREAD_FUNC(putmsg, (-1, NULL, NULL, 0))
  121. MAKE_CANCEL_THREAD_FUNC(putpmsg, (-1, NULL, NULL, 0, 0))
  122. MAKE_CANCEL_THREAD_FUNC(pwrite, (-1, NULL, 0, 0))
  123. MAKE_CANCEL_THREAD_FUNC(read, (-1, NULL, 0))
  124. MAKE_CANCEL_THREAD_FUNC(readv, (-1, NULL, 0))
  125. MAKE_CANCEL_THREAD_FUNC(recv, (-1, NULL, 0, 0))
  126. MAKE_CANCEL_THREAD_FUNC(recvfrom, (-1, NULL, 0, 0, NULL, NULL))
  127. MAKE_CANCEL_THREAD_FUNC(recvmsg, (-1, NULL, 0))
  128. MAKE_CANCEL_THREAD_FUNC(select, (0, NULL, NULL, NULL, NULL))
  129. MAKE_CANCEL_THREAD_FUNC_EX(sem_timedwait, (&sem, &zero_sec), help_sem_setup())
  130. MAKE_CANCEL_THREAD_FUNC_EX(sem_wait, (&sem), help_sem_setup())
  131. MAKE_CANCEL_THREAD_FUNC(send, (-1, NULL, 0, 0))
  132. MAKE_CANCEL_THREAD_FUNC(sendmsg, (-1, NULL, 0))
  133. MAKE_CANCEL_THREAD_FUNC(sendto, (-1, NULL, 0, 0, NULL, 0))
  134. MAKE_CANCEL_THREAD_FUNC(sigpause, (0))
  135. MAKE_CANCEL_THREAD_FUNC(sigsuspend, (NULL))
  136. MAKE_CANCEL_THREAD_FUNC(sigtimedwait, (NULL, NULL, NULL))
  137. MAKE_CANCEL_THREAD_FUNC(sigwait, (NULL, NULL))
  138. MAKE_CANCEL_THREAD_FUNC(sigwaitinfo, (NULL, NULL))
  139. MAKE_CANCEL_THREAD_FUNC(sleep, (0))
  140. MAKE_CANCEL_THREAD_FUNC(system, (""))
  141. MAKE_CANCEL_THREAD_FUNC(tcdrain, (-1))
  142. MAKE_CANCEL_THREAD_FUNC(usleep, (0))
  143. MAKE_CANCEL_THREAD_FUNC(wait, (NULL))
  144. MAKE_CANCEL_THREAD_FUNC(waitid, (0, 0, NULL, 0))
  145. MAKE_CANCEL_THREAD_FUNC(waitpid, (-1, NULL, 0))
  146. MAKE_CANCEL_THREAD_FUNC(write, (-1, NULL, 0))
  147. MAKE_CANCEL_THREAD_FUNC(writev, (-1, NULL, 0))
  148. /* test a few variations that should not cancel ... */
  149. MAKE_CANCEL_THREAD_FUNC_RE(fcntl_another, fcntl, (0, F_GETFD))
  150. /* main test that creates thread, cancels it, etc... */
  151. int _test_func(const char *func_name, void *(*func)(void*), const int should_cancel)
  152. {
  153. int ret;
  154. pthread_t cancel_thread_id;
  155. ++cnt;
  156. printf("testing %-30s ", func_name);
  157. printf(".");
  158. if (signal(SIGALRM, cancel_timeout) == SIG_ERR) {
  159. perror("unable to bind SIGALRM");
  160. exit(-1);
  161. }
  162. printf(".");
  163. ready = false;
  164. pthread_create(&cancel_thread_id, NULL, func, NULL);
  165. printf(".");
  166. while (!ready)
  167. sched_yield();
  168. printf(".");
  169. if (pthread_cancel(cancel_thread_id)) {
  170. perror("unable to cancel thread");
  171. exit(-1);
  172. }
  173. printf(".");
  174. alarm(5);
  175. while (ready)
  176. sched_yield();
  177. printf(".");
  178. ret = (!!!alarm(0) == should_cancel);
  179. if (ret)
  180. printf(" failed ;(\n");
  181. else
  182. printf(" OK!\n");
  183. return ret;
  184. }
  185. #define TEST_FUNC(f) _test_func(#f, cancel_thread_##f, 1)
  186. #define TEST_FUNC_RE(f) _test_func(#f, cancel_thread_##f, 0)
  187. int main(int argc, char *argv[])
  188. {
  189. int ret = 0;
  190. setbuf(stdout, NULL);
  191. cnt = 0;
  192. ret += TEST_FUNC(accept);
  193. ret += TEST_FUNC(aio_suspend);
  194. ret += TEST_FUNC(clock_nanosleep);
  195. ret += TEST_FUNC(close);
  196. ret += TEST_FUNC(connect);
  197. ret += TEST_FUNC(creat);
  198. ret += TEST_FUNC(fcntl);
  199. ret += TEST_FUNC(fdatasync);
  200. ret += TEST_FUNC(fsync);
  201. ret += TEST_FUNC(getmsg);
  202. ret += TEST_FUNC(getpmsg);
  203. ret += TEST_FUNC(lockf);
  204. ret += TEST_FUNC(mq_receive);
  205. ret += TEST_FUNC(mq_send);
  206. ret += TEST_FUNC(mq_timedreceive);
  207. ret += TEST_FUNC(mq_timedsend);
  208. ret += TEST_FUNC(msgrcv);
  209. ret += TEST_FUNC(msgsnd);
  210. ret += TEST_FUNC(msync);
  211. ret += TEST_FUNC(nanosleep);
  212. ret += TEST_FUNC(open);
  213. ret += TEST_FUNC(pause);
  214. ret += TEST_FUNC(poll);
  215. ret += TEST_FUNC(pread);
  216. ret += TEST_FUNC(pselect);
  217. ret += TEST_FUNC(pthread_cond_timedwait);
  218. ret += TEST_FUNC(pthread_cond_wait);
  219. /*ret += TEST_FUNC(pthread_join);*/
  220. ret += TEST_FUNC(pthread_testcancel);
  221. ret += TEST_FUNC(putmsg);
  222. ret += TEST_FUNC(putpmsg);
  223. ret += TEST_FUNC(pwrite);
  224. ret += TEST_FUNC(read);
  225. ret += TEST_FUNC(readv);
  226. ret += TEST_FUNC(recv);
  227. ret += TEST_FUNC(recvfrom);
  228. ret += TEST_FUNC(recvmsg);
  229. ret += TEST_FUNC(select);
  230. ret += TEST_FUNC(sem_timedwait);
  231. ret += TEST_FUNC(sem_wait);
  232. ret += TEST_FUNC(send);
  233. ret += TEST_FUNC(sendmsg);
  234. ret += TEST_FUNC(sendto);
  235. ret += TEST_FUNC(sigpause);
  236. ret += TEST_FUNC(sigsuspend);
  237. ret += TEST_FUNC(sigtimedwait);
  238. ret += TEST_FUNC(sigwait);
  239. ret += TEST_FUNC(sigwaitinfo);
  240. ret += TEST_FUNC(sleep);
  241. ret += TEST_FUNC(system);
  242. ret += TEST_FUNC(tcdrain);
  243. ret += TEST_FUNC(usleep);
  244. ret += TEST_FUNC(wait);
  245. ret += TEST_FUNC(waitid);
  246. ret += TEST_FUNC(waitpid);
  247. ret += TEST_FUNC(write);
  248. ret += TEST_FUNC(writev);
  249. ret += TEST_FUNC_RE(fcntl_another);
  250. if (ret)
  251. printf("!!! %i / %i tests failed\n", ret, cnt);
  252. return ret;
  253. }