tst-mqueue1.c 9.0 KB

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