1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** POSIX wrapper for THREADX */
16 /** */
17 /** */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 /* Include necessary system files. */
23
24 #include "tx_api.h" /* Threadx API */
25 #include "pthread.h" /* Posix API */
26 #include "px_int.h" /* Posix helper functions */
27
28 /**************************************************************************/
29 /* */
30 /* FUNCTION RELEASE */
31 /* */
32 /* posix_mq_create PORTABLE C */
33 /* 6.2.0 */
34 /* AUTHOR */
35 /* */
36 /* William E. Lamie, Microsoft Corporation */
37 /* */
38 /* DESCRIPTION */
39 /* */
40 /* This subroutine creates and initializes a message queue */
41 /* As the message length is user defined, message pointer and message */
42 /* length is stored in a ThreadX queue(instead of the actual message) */
43 /* The actual message is stored in a dedicated byte pool for the */
44 /* queue */
45 /* */
46 /* */
47 /* INPUT */
48 /* */
49 /* mq_name name of the Queue */
50 /* msgq_attr Pointer to mq_attr structure */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* posix_q If success */
55 /* NULL If failure */
56 /* */
57 /* CALLS */
58 /* */
59 /* posix_in_thread_context Make sure caller is thread */
60 /* tx_queue_create to create a ThreadX Queue */
61 /* posix_internal_error Generic error Handler */
62 /* posix_memory_allocate to create a byte pool */
63 /* tx_queue_delete to delete the queue */
64 /* posix_putback_queue to delete the queue */
65 /* tx_byte_pool_create to create a byte pool */
66 /* */
67 /* CALLED BY */
68 /* */
69 /* POSIX internal Code */
70 /* */
71 /* RELEASE HISTORY */
72 /* */
73 /* DATE NAME DESCRIPTION */
74 /* */
75 /* 06-02-2021 William E. Lamie Initial Version 6.1.7 */
76 /* 10-31-2022 Scott Larson Add 64-bit support, */
77 /* resulting in version 6.2.0 */
78 /* */
79 /**************************************************************************/
posix_mq_create(const CHAR * mq_name,struct mq_attr * msgq_attr)80 POSIX_MSG_QUEUE * posix_mq_create (const CHAR * mq_name,
81 struct mq_attr * msgq_attr)
82 {
83
84 TX_INTERRUPT_SAVE_AREA
85
86 POSIX_MSG_QUEUE *posix_q;
87 UINT temp1;
88 VOID *bp;
89 INT retval;
90 ULONG size;
91 TX_QUEUE *TheQ;
92
93 /* Make sure we're calling this routine from a thread context. */
94 if (!posix_in_thread_context())
95 {
96 /* return POSIX error. */
97 posix_internal_error(444);
98
99 /* return error. */
100 return ((POSIX_MSG_QUEUE *)ERROR);
101 }
102 /* Disable interrupts.*/
103 TX_DISABLE
104
105 /* Get a new queue from the POSIX queue pool. */
106 /* Make sure we have enough space for the size. */
107
108 posix_q = posix_get_new_queue(msgq_attr->mq_maxmsg);
109
110 /* Make sure we actually got a queue. */
111 if (!posix_q)
112 {
113 /* Restore interrupts. */
114 TX_RESTORE
115
116 /* User configuration error - not enough memory. */
117 posix_errno = EBADF;
118 posix_set_pthread_errno(EBADF);
119
120 /* Return ERROR. */
121 return(TX_NULL);
122 }
123
124 /* Now create a ThreadX message queue.
125 to store only the message pointer and message length. */
126 temp1 = tx_queue_create((&(posix_q->queue)),
127 (CHAR *)mq_name,
128 TX_POSIX_MESSAGE_SIZE,
129 posix_q->storage,
130 (msgq_attr->mq_maxmsg * (sizeof(ULONG) * TX_POSIX_MESSAGE_SIZE)));
131
132 /* Make sure it worked. */
133 if (temp1 != TX_SUCCESS)
134 {
135 /*. Return generic error. */
136 posix_internal_error(188);
137
138 /* Restore interrupts. */
139 TX_RESTORE
140
141 /* Return ERROR. */
142 return(TX_NULL);
143 }
144 /* Restore no. of maximum messages. */
145 posix_q->q_attr.mq_maxmsg = msgq_attr->mq_maxmsg;
146
147 /* Restore maximum message length. */
148 posix_q->q_attr.mq_msgsize = msgq_attr->mq_msgsize;
149
150 /* Flags are stored in que descriptor structure and
151 not in mq_att structure. */
152
153 /* Create a byte pool for the queue.
154 Determine how much memory we need to store all messages in this queue.
155 11 bytes are added to counter overhead as well as alignment problem if any. */
156 size = ( ((msgq_attr->mq_maxmsg) + 1) * (msgq_attr->mq_msgsize + 11) );
157
158 if(size < 100)
159 size = 100;
160
161 /* Now attempt to allocate that much memory for the queue. */
162
163 retval = posix_memory_allocate(size,&bp);
164
165 /* Make sure we obtained the memory we requested. */
166 if (retval)
167 {
168 /* Created queue Control block, got memory to store message pointers
169 and lengths which means that created a fixed length message queue but
170 not enough memory to store actual messages. */
171
172 /* Delete the queue. */
173
174 /* Assign a temporary variable for clarity. */
175 TheQ = (TX_QUEUE * )posix_q;
176 retval = tx_queue_delete(TheQ);
177
178 /* Make sure the queue was deleted. */
179 if (retval != TX_SUCCESS)
180 {
181 /* Return generic error. */
182 posix_internal_error(799);
183
184 /* Restore interrupts. */
185 TX_RESTORE
186
187 /* Return ERROR. */
188 return(TX_NULL);
189 }
190 /* Put the queue back into the POSIX queue pool. */
191 posix_putback_queue(TheQ);
192
193 /* User configuration error - not enough memory. */
194 posix_errno = EBADF;
195 posix_set_pthread_errno(EBADF);
196 TX_RESTORE;
197
198 /* Return ERROR. */
199 return(TX_NULL);
200 }
201 /* Create a ThreadX byte pool that will provide memory needed by the queue. */
202 retval = tx_byte_pool_create((&(posix_q->vq_message_area)), "POSIX Queue",
203 bp, size);
204
205 /* Make sure the byte pool was created successfully. */
206 if (retval)
207 {
208 /* Error creating byte pool. */
209 posix_internal_error(9999);
210
211 /* Restore interrupts. */
212 TX_RESTORE
213
214 /* Return ERROR.*/
215 return(TX_NULL);
216 }
217
218 posix_q->name = (CHAR*) mq_name;
219
220 /* Restore interrupts. */
221 TX_RESTORE
222
223 /* All done. */
224 return(posix_q);
225 }
226