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