cancellation-points.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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_AIO__)
  30. # include <aio.h>
  31. #else
  32. STUB(aio_suspend, (void *p, int n, const void *p2))
  33. #endif
  34. #if 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. #ifdef __UCLIBC_SUSV4_LEGACY__
  135. MAKE_CANCEL_THREAD_FUNC(sigpause, (0))
  136. #endif
  137. MAKE_CANCEL_THREAD_FUNC(sigsuspend, (NULL))
  138. MAKE_CANCEL_THREAD_FUNC(sigtimedwait, (NULL, NULL, NULL))
  139. MAKE_CANCEL_THREAD_FUNC(sigwait, (NULL, NULL))
  140. MAKE_CANCEL_THREAD_FUNC(sigwaitinfo, (NULL, NULL))
  141. MAKE_CANCEL_THREAD_FUNC(sleep, (0))
  142. MAKE_CANCEL_THREAD_FUNC(system, (""))
  143. MAKE_CANCEL_THREAD_FUNC(tcdrain, (-1))
  144. #ifdef __UCLIBC_SUSV3_LEGACY__
  145. MAKE_CANCEL_THREAD_FUNC(usleep, (0))
  146. #endif
  147. MAKE_CANCEL_THREAD_FUNC(wait, (NULL))
  148. MAKE_CANCEL_THREAD_FUNC(waitid, (0, 0, NULL, 0))
  149. MAKE_CANCEL_THREAD_FUNC(waitpid, (-1, NULL, 0))
  150. MAKE_CANCEL_THREAD_FUNC(write, (-1, NULL, 0))
  151. MAKE_CANCEL_THREAD_FUNC(writev, (-1, NULL, 0))
  152. /* test a few variations that should not cancel ... */
  153. MAKE_CANCEL_THREAD_FUNC_RE(fcntl_another, fcntl, (0, F_GETFD))
  154. /* main test that creates thread, cancels it, etc... */
  155. int _test_func(const char *func_name, void *(*func)(void*), const int should_cancel)
  156. {
  157. int ret;
  158. pthread_t cancel_thread_id;
  159. ++cnt;
  160. printf("testing %-30s ", func_name);
  161. printf(".");
  162. if (signal(SIGALRM, cancel_timeout) == SIG_ERR) {
  163. perror("unable to bind SIGALRM");
  164. exit(-1);
  165. }
  166. printf(".");
  167. ready = false;
  168. pthread_create(&cancel_thread_id, NULL, func, NULL);
  169. printf(".");
  170. while (!ready)
  171. sched_yield();
  172. printf(".");
  173. if (pthread_cancel(cancel_thread_id)) {
  174. perror("unable to cancel thread");
  175. exit(-1);
  176. }
  177. printf(".");
  178. alarm(5);
  179. while (ready)
  180. sched_yield();
  181. printf(".");
  182. ret = (!!!alarm(0) == should_cancel);
  183. if (ret)
  184. printf(" failed ;(\n");
  185. else
  186. printf(" OK!\n");
  187. return ret;
  188. }
  189. #define TEST_FUNC(f) _test_func(#f, cancel_thread_##f, 1)
  190. #define TEST_FUNC_RE(f) _test_func(#f, cancel_thread_##f, 0)
  191. int main(int argc, char *argv[])
  192. {
  193. int ret = 0;
  194. setbuf(stdout, NULL);
  195. cnt = 0;
  196. ret += TEST_FUNC(accept);
  197. ret += TEST_FUNC(aio_suspend);
  198. ret += TEST_FUNC(clock_nanosleep);
  199. ret += TEST_FUNC(close);
  200. ret += TEST_FUNC(connect);
  201. ret += TEST_FUNC(creat);
  202. ret += TEST_FUNC(fcntl);
  203. ret += TEST_FUNC(fdatasync);
  204. ret += TEST_FUNC(fsync);
  205. ret += TEST_FUNC(getmsg);
  206. ret += TEST_FUNC(getpmsg);
  207. ret += TEST_FUNC(lockf);
  208. ret += TEST_FUNC(mq_receive);
  209. ret += TEST_FUNC(mq_send);
  210. ret += TEST_FUNC(mq_timedreceive);
  211. ret += TEST_FUNC(mq_timedsend);
  212. ret += TEST_FUNC(msgrcv);
  213. ret += TEST_FUNC(msgsnd);
  214. ret += TEST_FUNC(msync);
  215. ret += TEST_FUNC(nanosleep);
  216. ret += TEST_FUNC(open);
  217. ret += TEST_FUNC(pause);
  218. ret += TEST_FUNC(poll);
  219. ret += TEST_FUNC(pread);
  220. ret += TEST_FUNC(pselect);
  221. ret += TEST_FUNC(pthread_cond_timedwait);
  222. ret += TEST_FUNC(pthread_cond_wait);
  223. /*ret += TEST_FUNC(pthread_join);*/
  224. ret += TEST_FUNC(pthread_testcancel);
  225. ret += TEST_FUNC(putmsg);
  226. ret += TEST_FUNC(putpmsg);
  227. ret += TEST_FUNC(pwrite);
  228. ret += TEST_FUNC(read);
  229. ret += TEST_FUNC(readv);
  230. ret += TEST_FUNC(recv);
  231. ret += TEST_FUNC(recvfrom);
  232. ret += TEST_FUNC(recvmsg);
  233. ret += TEST_FUNC(select);
  234. ret += TEST_FUNC(sem_timedwait);
  235. ret += TEST_FUNC(sem_wait);
  236. ret += TEST_FUNC(send);
  237. ret += TEST_FUNC(sendmsg);
  238. ret += TEST_FUNC(sendto);
  239. ret += TEST_FUNC(sigpause);
  240. ret += TEST_FUNC(sigsuspend);
  241. ret += TEST_FUNC(sigtimedwait);
  242. ret += TEST_FUNC(sigwait);
  243. ret += TEST_FUNC(sigwaitinfo);
  244. ret += TEST_FUNC(sleep);
  245. ret += TEST_FUNC(system);
  246. ret += TEST_FUNC(tcdrain);
  247. #ifdef __UCLIBC_SUSV3_LEGACY__
  248. ret += TEST_FUNC(usleep);
  249. #endif
  250. ret += TEST_FUNC(wait);
  251. ret += TEST_FUNC(waitid);
  252. ret += TEST_FUNC(waitpid);
  253. ret += TEST_FUNC(write);
  254. ret += TEST_FUNC(writev);
  255. ret += TEST_FUNC_RE(fcntl_another);
  256. if (ret)
  257. printf("!!! %i / %i tests failed\n", ret, cnt);
  258. return ret;
  259. }