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