mqueue.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. */
  9. #include <string.h>
  10. #include <fcntl.h>
  11. #include <sys/signal.h>
  12. #include <sys/time.h>
  13. #include <sys/errno.h>
  14. #include <rtthread.h>
  15. #include <limits.h>
  16. #include "mqueue.h"
  17. static mqdes_t posix_mq_list = RT_NULL;
  18. static struct rt_semaphore posix_mq_lock;
  19. /* initialize posix mqueue */
  20. static int posix_mq_system_init(void)
  21. {
  22. rt_sem_init(&posix_mq_lock, "pmq", 1, RT_IPC_FLAG_FIFO);
  23. return 0;
  24. }
  25. INIT_COMPONENT_EXPORT(posix_mq_system_init);
  26. rt_inline void posix_mq_insert(mqdes_t pmq)
  27. {
  28. if (posix_mq_list == RT_NULL)
  29. pmq->mq_id = 1;
  30. else
  31. pmq->mq_id = posix_mq_list->mq_id + 1;
  32. pmq->next = posix_mq_list;
  33. posix_mq_list = pmq;
  34. }
  35. static void posix_mq_delete(mqdes_t pmq)
  36. {
  37. mqdes_t iter;
  38. if (posix_mq_list == pmq)
  39. {
  40. posix_mq_list = pmq->next;
  41. rt_mq_delete(pmq->mq);
  42. rt_free(pmq);
  43. return;
  44. }
  45. for (iter = posix_mq_list; iter->next != RT_NULL; iter = iter->next)
  46. {
  47. if (iter->next == pmq)
  48. {
  49. /* delete this mq */
  50. if (pmq->next != RT_NULL)
  51. iter->next = pmq->next;
  52. else
  53. iter->next = RT_NULL;
  54. /* delete RT-Thread mqueue */
  55. rt_mq_delete(pmq->mq);
  56. rt_free(pmq);
  57. return ;
  58. }
  59. }
  60. }
  61. static mqdes_t posix_mq_find(const char *name)
  62. {
  63. mqdes_t iter;
  64. rt_object_t object;
  65. for (iter = posix_mq_list; iter != RT_NULL; iter = iter->next)
  66. {
  67. object = (rt_object_t)(iter->mq);
  68. if (strncmp(object->name, name, RT_NAME_MAX) == 0)
  69. {
  70. return iter;
  71. }
  72. }
  73. return RT_NULL;
  74. }
  75. static mqdes_t posix_mq_id_find(mqd_t id)
  76. {
  77. for (mqdes_t iter = posix_mq_list; iter != RT_NULL; iter = iter->next)
  78. if (iter->mq_id == id)
  79. return iter;
  80. return RT_NULL;
  81. }
  82. int mq_setattr(mqd_t id,
  83. const struct mq_attr *mqstat,
  84. struct mq_attr *omqstat)
  85. {
  86. if (mqstat == RT_NULL)
  87. return mq_getattr(id, omqstat);
  88. else
  89. rt_set_errno(-RT_ERROR);
  90. return -1;
  91. }
  92. RTM_EXPORT(mq_setattr);
  93. int mq_getattr(mqd_t id, struct mq_attr *mqstat)
  94. {
  95. rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER);
  96. mqdes_t mqdes = posix_mq_id_find(id);
  97. rt_sem_release(&posix_mq_lock);
  98. if ((mqdes == RT_NULL) || mqstat == RT_NULL)
  99. {
  100. rt_set_errno(EBADF);
  101. return -1;
  102. }
  103. mqstat->mq_maxmsg = mqdes->mq->max_msgs;
  104. mqstat->mq_msgsize = mqdes->mq->msg_size;
  105. mqstat->mq_curmsgs = 0;
  106. mqstat->mq_flags = 0;
  107. return 0;
  108. }
  109. RTM_EXPORT(mq_getattr);
  110. mqd_t mq_open(const char *name, int oflag, ...)
  111. {
  112. va_list arg;
  113. mode_t mode;
  114. mqdes_t mqdes = RT_NULL;
  115. struct mq_attr *attr = RT_NULL;
  116. /* lock posix mqueue list */
  117. rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER);
  118. int len = rt_strlen(name);
  119. if (len > RT_NAME_MAX)
  120. {
  121. rt_set_errno(ENAMETOOLONG);
  122. goto __return;
  123. }
  124. mqdes = posix_mq_find(name);
  125. if (mqdes != RT_NULL)
  126. {
  127. if (oflag & O_CREAT && oflag & O_EXCL)
  128. {
  129. rt_set_errno(EEXIST);
  130. rt_sem_release(&posix_mq_lock);
  131. return (mqd_t)(-1);
  132. }
  133. mqdes->refcount++; /* increase reference count */
  134. }
  135. else if (oflag & O_CREAT)
  136. {
  137. va_start(arg, oflag);
  138. mode = (mode_t)va_arg(arg, unsigned int);
  139. mode = (mode_t)mode; /* self-assignment avoids compiler optimization */
  140. attr = (struct mq_attr *)va_arg(arg, struct mq_attr *);
  141. attr = (struct mq_attr *)attr; /* self-assignment avoids compiler optimization */
  142. va_end(arg);
  143. if (attr->mq_maxmsg <= 0)
  144. {
  145. rt_set_errno(EINVAL);
  146. goto __return;
  147. }
  148. mqdes = (mqdes_t) rt_malloc (sizeof(struct mqdes));
  149. if (mqdes == RT_NULL)
  150. {
  151. rt_set_errno(ENFILE);
  152. goto __return;
  153. }
  154. /* create RT-Thread message queue */
  155. mqdes->mq = rt_mq_create(name, attr->mq_msgsize, attr->mq_maxmsg, RT_IPC_FLAG_FIFO);
  156. if (mqdes->mq == RT_NULL) /* create failed */
  157. {
  158. rt_set_errno(ENFILE);
  159. goto __return;
  160. }
  161. /* initialize reference count */
  162. mqdes->refcount = 1;
  163. mqdes->unlinked = 0;
  164. /* insert mq to posix mq list */
  165. posix_mq_insert(mqdes);
  166. }
  167. else
  168. {
  169. rt_set_errno(ENOENT);
  170. goto __return;
  171. }
  172. rt_sem_release(&posix_mq_lock);
  173. return (mqd_t)(mqdes->mq_id);
  174. __return:
  175. /* release lock */
  176. rt_sem_release(&posix_mq_lock);
  177. /* release allocated memory */
  178. if (mqdes != RT_NULL)
  179. {
  180. if (mqdes->mq != RT_NULL)
  181. {
  182. /* delete RT-Thread message queue */
  183. rt_mq_delete(mqdes->mq);
  184. }
  185. rt_free(mqdes);
  186. }
  187. return (mqd_t)(-1);
  188. }
  189. RTM_EXPORT(mq_open);
  190. ssize_t mq_receive(mqd_t id, char *msg_ptr, size_t msg_len, unsigned *msg_prio)
  191. {
  192. rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER);
  193. mqdes_t mqdes = posix_mq_id_find(id);
  194. rt_sem_release(&posix_mq_lock);
  195. rt_err_t result;
  196. if ((mqdes == RT_NULL) || (msg_ptr == RT_NULL))
  197. {
  198. rt_set_errno(EINVAL);
  199. return -1;
  200. }
  201. result = rt_mq_recv(mqdes->mq, msg_ptr, msg_len, RT_WAITING_FOREVER);
  202. if (result >= 0)
  203. return rt_strlen(msg_ptr);
  204. rt_set_errno(EBADF);
  205. return -1;
  206. }
  207. RTM_EXPORT(mq_receive);
  208. int mq_send(mqd_t id, const char *msg_ptr, size_t msg_len, unsigned msg_prio)
  209. {
  210. rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER);
  211. mqdes_t mqdes = posix_mq_id_find(id);
  212. rt_sem_release(&posix_mq_lock);
  213. rt_err_t result;
  214. if ((mqdes == RT_NULL) || (msg_ptr == RT_NULL))
  215. {
  216. rt_set_errno(EINVAL);
  217. return -1;
  218. }
  219. result = rt_mq_send(mqdes->mq, (void*)msg_ptr, msg_len);
  220. if (result == RT_EOK)
  221. return 0;
  222. rt_set_errno(EBADF);
  223. return -1;
  224. }
  225. RTM_EXPORT(mq_send);
  226. ssize_t mq_timedreceive(mqd_t id,
  227. char *msg_ptr,
  228. size_t msg_len,
  229. unsigned *msg_prio,
  230. const struct timespec *abs_timeout)
  231. {
  232. rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER);
  233. mqdes_t mqdes = posix_mq_id_find(id);
  234. rt_sem_release(&posix_mq_lock);
  235. int tick = 0;
  236. rt_err_t result;
  237. /* parameters check */
  238. if ((mqdes == RT_NULL) || (msg_ptr == RT_NULL))
  239. {
  240. rt_set_errno(EINVAL);
  241. return -1;
  242. }
  243. if (abs_timeout != RT_NULL)
  244. tick = rt_timespec_to_tick(abs_timeout);
  245. result = rt_mq_recv(mqdes->mq, msg_ptr, msg_len, tick);
  246. if (result >= 0)
  247. return rt_strlen(msg_ptr);
  248. if (result == -RT_ETIMEOUT)
  249. rt_set_errno(ETIMEDOUT);
  250. else if (result == -RT_ERROR)
  251. rt_set_errno(EMSGSIZE);
  252. else
  253. rt_set_errno(EBADMSG);
  254. return -1;
  255. }
  256. RTM_EXPORT(mq_timedreceive);
  257. int mq_timedsend(mqd_t id,
  258. const char *msg_ptr,
  259. size_t msg_len,
  260. unsigned msg_prio,
  261. const struct timespec *abs_timeout)
  262. {
  263. /* RT-Thread does not support timed send */
  264. return mq_send(id, msg_ptr, msg_len, msg_prio);
  265. }
  266. RTM_EXPORT(mq_timedsend);
  267. int mq_notify(mqd_t id, const struct sigevent *notification)
  268. {
  269. rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER);
  270. mqdes_t mqdes = posix_mq_id_find(id);
  271. rt_sem_release(&posix_mq_lock);
  272. if (mqdes == RT_NULL || mqdes->refcount == 0)
  273. {
  274. rt_set_errno(EBADF);
  275. return -1;
  276. }
  277. rt_set_errno(-RT_ERROR);
  278. return -1;
  279. }
  280. RTM_EXPORT(mq_notify);
  281. int mq_close(mqd_t id)
  282. {
  283. rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER);
  284. mqdes_t mqdes = posix_mq_id_find(id);
  285. rt_sem_release(&posix_mq_lock);
  286. if (mqdes == RT_NULL)
  287. {
  288. rt_set_errno(EBADF);
  289. return -1;
  290. }
  291. /* lock posix mqueue list */
  292. rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER);
  293. mqdes->refcount --;
  294. if (mqdes->refcount == 0)
  295. {
  296. /* delete from posix mqueue list */
  297. if (mqdes->unlinked)
  298. posix_mq_delete(mqdes);
  299. }
  300. rt_sem_release(&posix_mq_lock);
  301. return 0;
  302. }
  303. RTM_EXPORT(mq_close);
  304. /**
  305. * @brief This function will remove a message queue (REALTIME).
  306. *
  307. * @note The mq_unlink() function shall remove the message queue named by the string name.
  308. * If one or more processes have the message queue open when mq_unlink() is called,
  309. * destruction of the message queue shall be postponed until all references to the message queue have been closed.
  310. * However, the mq_unlink() call need not block until all references have been closed; it may return immediately.
  311. *
  312. * After a successful call to mq_unlink(), reuse of the name shall subsequently cause mq_open() to behave as if
  313. * no message queue of this name exists (that is, mq_open() will fail if O_CREAT is not set,
  314. * or will create a new message queue if O_CREAT is set).
  315. *
  316. * @param name is the name of the message queue.
  317. *
  318. * @return Upon successful completion, the function shall return a value of zero.
  319. * Otherwise, the named message queue shall be unchanged by this function call,
  320. * and the function shall return a value of -1 and set errno to indicate the error.
  321. *
  322. * @warning This function can ONLY be called in the thread context, you can use RT_DEBUG_IN_THREAD_CONTEXT to
  323. * check the context.
  324. * The mq_unlink() function shall fail if:
  325. * [EACCES]
  326. * Permission is denied to unlink the named message queue.
  327. * [EINTR]
  328. * The call to mq_unlink() blocked waiting for all references to the named message queue to be closed and a signal interrupted the call.
  329. * [ENOENT]
  330. * The named message queue does not exist.
  331. * The mq_unlink() function may fail if:
  332. * [ENAMETOOLONG]
  333. * The length of the name argument exceeds {_POSIX_PATH_MAX} on systems that do not support the XSI option
  334. * or exceeds {_XOPEN_PATH_MAX} on XSI systems,or has a pathname component that is longer than {_POSIX_NAME_MAX} on systems that do
  335. * not support the XSI option or longer than {_XOPEN_NAME_MAX} on XSI systems.A call to mq_unlink() with a name argument that contains
  336. * the same message queue name as was previously used in a successful mq_open() call shall not give an [ENAMETOOLONG] error.
  337. */
  338. int mq_unlink(const char *name)
  339. {
  340. mqdes_t pmq;
  341. /* lock posix mqueue list */
  342. rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER);
  343. pmq = posix_mq_find(name);
  344. if (pmq != RT_NULL)
  345. {
  346. pmq->unlinked = 1;
  347. if (pmq->refcount == 0)
  348. {
  349. /* remove this mqueue */
  350. posix_mq_delete(pmq);
  351. }
  352. rt_sem_release(&posix_mq_lock);
  353. return 0;
  354. }
  355. rt_sem_release(&posix_mq_lock);
  356. /* no this entry */
  357. rt_set_errno(ENOENT);
  358. return -1;
  359. }
  360. RTM_EXPORT(mq_unlink);