tst-mqueue1.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /* Test message queue passing.
  2. Copyright (C) 2004 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
  5. The GNU C Library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with the GNU C Library; if not, see
  15. <http://www.gnu.org/licenses/>. */
  16. #include <errno.h>
  17. #include <fcntl.h>
  18. #include <mqueue.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <sys/wait.h>
  23. #include <time.h>
  24. #include <unistd.h>
  25. #include "tst-mqueue.h"
  26. #include "../test-skeleton.h"
  27. static int
  28. intcmp (const void *a, const void *b)
  29. {
  30. if (*(unsigned char *)a < *(unsigned char *)b)
  31. return 1;
  32. if (*(unsigned char *)a > *(unsigned char *)b)
  33. return -1;
  34. return 0;
  35. }
  36. static int
  37. check_attrs (struct mq_attr *attr, int nonblock, long cnt)
  38. {
  39. int result = 0;
  40. if (attr->mq_maxmsg != 10 || attr->mq_msgsize != 1)
  41. {
  42. printf ("attributes don't match those passed to mq_open\n"
  43. "mq_maxmsg %ld, mq_msgsize %ld\n",
  44. attr->mq_maxmsg, attr->mq_msgsize);
  45. result = 1;
  46. }
  47. if ((attr->mq_flags & O_NONBLOCK) != nonblock)
  48. {
  49. printf ("mq_flags %lx != %x\n", (attr->mq_flags & O_NONBLOCK), nonblock);
  50. result = 1;
  51. }
  52. if (attr->mq_curmsgs != cnt)
  53. {
  54. printf ("mq_curmsgs %ld != %ld\n", attr->mq_curmsgs, cnt);
  55. result = 1;
  56. }
  57. return result;
  58. }
  59. static int
  60. do_one_test (mqd_t q, const char *name, int nonblock)
  61. {
  62. int result = 0;
  63. char v []
  64. = { 0x32, 0x62, 0x22, 0x31, 0x11, 0x73, 0x61, 0x21, 0x72, 0x71, 0x81 };
  65. struct mq_attr attr;
  66. memset (&attr, 0xaa, sizeof (attr));
  67. if (mq_getattr (q, &attr) != 0)
  68. {
  69. printf ("mq_getattr failed: %m\n");
  70. result = 1;
  71. }
  72. else
  73. result |= check_attrs (&attr, nonblock, 0);
  74. if (mq_receive (q, &v[0], 1, NULL) != -1)
  75. {
  76. puts ("mq_receive on O_WRONLY mqd_t unexpectedly succeeded");
  77. result = 1;
  78. }
  79. else if (errno != EBADF)
  80. {
  81. printf ("mq_receive on O_WRONLY mqd_t did not fail with EBADF: %m\n");
  82. result = 1;
  83. }
  84. struct timespec ts;
  85. if (clock_gettime (CLOCK_REALTIME, &ts) == 0)
  86. --ts.tv_sec;
  87. else
  88. {
  89. ts.tv_sec = time (NULL) - 1;
  90. ts.tv_nsec = 0;
  91. }
  92. int ret;
  93. for (int i = 0; i < 10; ++i)
  94. {
  95. if (i & 1)
  96. ret = mq_send (q, &v[i], 1, v[i] >> 4);
  97. else
  98. ret = mq_timedsend (q, &v[i], 1, v[i] >> 4, &ts);
  99. if (ret)
  100. {
  101. printf ("mq_%ssend failed: %m\n", (i & 1) ? "" : "timed");
  102. result = 1;
  103. }
  104. }
  105. ret = mq_timedsend (q, &v[10], 1, 8, &ts);
  106. if (ret != -1)
  107. {
  108. puts ("mq_timedsend on full queue did not fail");
  109. result = 1;
  110. }
  111. else if (errno != (nonblock ? EAGAIN : ETIMEDOUT))
  112. {
  113. printf ("mq_timedsend on full queue did not fail with %s: %m\n",
  114. nonblock ? "EAGAIN" : "ETIMEDOUT");
  115. result = 1;
  116. }
  117. if (nonblock)
  118. {
  119. ret = mq_send (q, &v[10], 1, 8);
  120. if (ret != -1)
  121. {
  122. puts ("mq_send on full non-blocking queue did not fail");
  123. result = 1;
  124. }
  125. else if (errno != EAGAIN)
  126. {
  127. printf ("mq_send on full non-blocking queue did not fail"
  128. "with EAGAIN: %m\n");
  129. result = 1;
  130. }
  131. }
  132. memset (&attr, 0xaa, sizeof (attr));
  133. if (mq_getattr (q, &attr) != 0)
  134. {
  135. printf ("mq_getattr failed: %m\n");
  136. result = 1;
  137. }
  138. else
  139. result |= check_attrs (&attr, nonblock, 10);
  140. pid_t pid = fork ();
  141. if (pid == -1)
  142. {
  143. printf ("fork failed: %m\n");
  144. result = 1;
  145. }
  146. else if (pid == 0)
  147. {
  148. result = 0;
  149. if (mq_close (q) != 0)
  150. {
  151. printf ("mq_close in child failed: %m\n");
  152. result = 1;
  153. }
  154. q = mq_open (name, O_RDONLY | nonblock);
  155. if (q == (mqd_t) -1)
  156. {
  157. printf ("mq_open in child failed: %m\n");
  158. exit (1);
  159. }
  160. memset (&attr, 0xaa, sizeof (attr));
  161. if (mq_getattr (q, &attr) != 0)
  162. {
  163. printf ("mq_getattr failed: %m\n");
  164. result = 1;
  165. }
  166. else
  167. result |= check_attrs (&attr, nonblock, 10);
  168. char vr[11] = { };
  169. unsigned int prio;
  170. ssize_t rets;
  171. if (mq_send (q, &v[0], 1, 1) != -1)
  172. {
  173. puts ("mq_send on O_RDONLY mqd_t unexpectedly succeeded");
  174. result = 1;
  175. }
  176. else if (errno != EBADF)
  177. {
  178. printf ("mq_send on O_WRONLY mqd_t did not fail with EBADF: %m\n");
  179. result = 1;
  180. }
  181. for (int i = 0; i < 10; ++i)
  182. {
  183. if (i & 1)
  184. rets = mq_receive (q, &vr[i], 1, &prio);
  185. else
  186. rets = mq_timedreceive (q, &vr[i], 1, &prio, &ts);
  187. if (rets != 1)
  188. {
  189. if (rets == -1)
  190. printf ("mq_%sreceive failed: %m\n", (i & 1) ? "" : "timed");
  191. else
  192. printf ("mq_%sreceive returned %zd != 1\n",
  193. (i & 1) ? "" : "timed", rets);
  194. result = 1;
  195. }
  196. else if (prio != (unsigned int) vr[i] >> 4)
  197. {
  198. printf ("unexpected priority %x for value %02x\n", prio,
  199. vr[i]);
  200. result = 1;
  201. }
  202. }
  203. qsort (v, 10, 1, intcmp);
  204. if (memcmp (v, vr, 10) != 0)
  205. {
  206. puts ("messages not received in expected order");
  207. result = 1;
  208. }
  209. rets = mq_timedreceive (q, &vr[10], 1, &prio, &ts);
  210. if (rets != -1)
  211. {
  212. puts ("mq_timedreceive on empty queue did not fail");
  213. result = 1;
  214. }
  215. else if (errno != (nonblock ? EAGAIN : ETIMEDOUT))
  216. {
  217. printf ("mq_timedreceive on empty queue did not fail with %s: %m\n",
  218. nonblock ? "EAGAIN" : "ETIMEDOUT");
  219. result = 1;
  220. }
  221. if (nonblock)
  222. {
  223. ret = mq_receive (q, &vr[10], 1, &prio);
  224. if (ret != -1)
  225. {
  226. puts ("mq_receive on empty non-blocking queue did not fail");
  227. result = 1;
  228. }
  229. else if (errno != EAGAIN)
  230. {
  231. printf ("mq_receive on empty non-blocking queue did not fail"
  232. "with EAGAIN: %m\n");
  233. result = 1;
  234. }
  235. }
  236. memset (&attr, 0xaa, sizeof (attr));
  237. if (mq_getattr (q, &attr) != 0)
  238. {
  239. printf ("mq_getattr failed: %m\n");
  240. result = 1;
  241. }
  242. else
  243. result |= check_attrs (&attr, nonblock, 0);
  244. if (mq_close (q) != 0)
  245. {
  246. printf ("mq_close in child failed: %m\n");
  247. result = 1;
  248. }
  249. exit (result);
  250. }
  251. int status;
  252. if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
  253. {
  254. printf ("waitpid failed: %m\n");
  255. kill (pid, SIGKILL);
  256. result = 1;
  257. }
  258. else if (!WIFEXITED (status) || WEXITSTATUS (status))
  259. {
  260. printf ("child failed: %d\n", status);
  261. result = 1;
  262. }
  263. memset (&attr, 0xaa, sizeof (attr));
  264. if (mq_getattr (q, &attr) != 0)
  265. {
  266. printf ("mq_getattr failed: %m\n");
  267. result = 1;
  268. }
  269. else
  270. result |= check_attrs (&attr, nonblock, 0);
  271. return result;
  272. }
  273. #define TEST_FUNCTION do_test ()
  274. static int
  275. do_test (void)
  276. {
  277. int result = 0;
  278. char name[sizeof "/tst-mqueue1-" + sizeof (pid_t) * 3];
  279. snprintf (name, sizeof (name), "/tst-mqueue1-%u", getpid ());
  280. struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = 1 };
  281. mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_WRONLY, 0600, &attr);
  282. if (q == (mqd_t) -1)
  283. {
  284. printf ("mq_open failed with: %m\n");
  285. return result;
  286. }
  287. else
  288. add_temp_mq (name);
  289. result |= do_one_test (q, name, 0);
  290. mqd_t q2 = mq_open (name, O_WRONLY | O_NONBLOCK);
  291. if (q2 == (mqd_t) -1)
  292. {
  293. printf ("mq_open failed with: %m\n");
  294. q2 = q;
  295. result = 1;
  296. }
  297. else
  298. {
  299. if (mq_close (q) != 0)
  300. {
  301. printf ("mq_close in parent failed: %m\n");
  302. result = 1;
  303. }
  304. q = q2;
  305. result |= do_one_test (q, name, O_NONBLOCK);
  306. if (mq_getattr (q, &attr) != 0)
  307. {
  308. printf ("mq_getattr failed: %m\n");
  309. result = 1;
  310. }
  311. else
  312. {
  313. attr.mq_flags ^= O_NONBLOCK;
  314. struct mq_attr attr2;
  315. memset (&attr2, 0x55, sizeof (attr2));
  316. if (mq_setattr (q, &attr, &attr2) != 0)
  317. {
  318. printf ("mq_setattr failed: %m\n");
  319. result = 1;
  320. }
  321. else if (attr.mq_flags != (attr2.mq_flags ^ O_NONBLOCK)
  322. || attr.mq_maxmsg != attr2.mq_maxmsg
  323. || attr.mq_msgsize != attr2.mq_msgsize
  324. || attr.mq_curmsgs != 0
  325. || attr2.mq_curmsgs != 0)
  326. {
  327. puts ("mq_setattr returned unexpected values in *omqstat");
  328. result = 1;
  329. }
  330. else
  331. {
  332. result |= do_one_test (q, name, 0);
  333. if (mq_setattr (q, &attr2, NULL) != 0)
  334. {
  335. printf ("mq_setattr failed: %m\n");
  336. result = 1;
  337. }
  338. else
  339. result |= do_one_test (q, name, O_NONBLOCK);
  340. }
  341. }
  342. }
  343. if (mq_unlink (name) != 0)
  344. {
  345. printf ("mq_unlink failed: %m\n");
  346. result = 1;
  347. }
  348. if (mq_close (q) != 0)
  349. {
  350. printf ("mq_close in parent failed: %m\n");
  351. result = 1;
  352. }
  353. if (mq_close (q) != -1)
  354. {
  355. puts ("second mq_close did not fail");
  356. result = 1;
  357. }
  358. else if (errno != EBADF)
  359. {
  360. printf ("second mq_close did not fail with EBADF: %m\n");
  361. result = 1;
  362. }
  363. return result;
  364. }
  365. #include "../test-skeleton.c"