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 /*    mq_send                                             PORTABLE C      */
33 /*                                                           6.1.7        */
34 /*  AUTHOR                                                                */
35 /*                                                                        */
36 /*    William E. Lamie, Microsoft Corporation                             */
37 /*                                                                        */
38 /*  DESCRIPTION                                                           */
39 /*                                                                        */
40 /*    The mq_send() function puts a message of size msg_len and pointed to*/
41 /*    by msg_ptr into the queue indicated by mqdes. The new message has a */
42 /*    priority of msg_prio.                                               */
43 /*    The queue maintained is in priority order (priorities may range from*/
44 /*    0 to MQ_PRIO_MAX), and in FIFO order within the same priority.      */
45 /*                                                                        */
46 /*  INPUT                                                                 */
47 /*                                                                        */
48 /*    mqdes                             Queue descriptor                  */
49 /*    msg_ptr                           Message pointer                   */
50 /*    msg_len                           length of message                 */
51 /*    msg_prio                          Priority of the message           */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    OK                                no of bytes received              */
56 /*    ERROR                             If error occurs                   */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    tx_thread_identify                returns currently running thread  */
61 /*    tx_byte_allocate                  allocate memory                   */
62 /*    tx_queue_send                     ThreadX queue send                */
63 /*    posix_priority_search             search message for same priority  */
64 /*                                                                        */
65 /*                                                                        */
66 /*  CALLED BY                                                             */
67 /*                                                                        */
68 /*    Application Code                                                    */
69 /*                                                                        */
70 /*  RELEASE HISTORY                                                       */
71 /*                                                                        */
72 /*    DATE              NAME                      DESCRIPTION             */
73 /*                                                                        */
74 /*  06-02-2021      William E. Lamie        Initial Version 6.1.7         */
75 /*  10-31-2022      Scott Larson            Add 64-bit support,           */
76 /*                                            resulting in version 6.2.0  */
77 /*                                                                        */
78 /**************************************************************************/
mq_send(mqd_t mqdes,const CHAR * msg_ptr,size_t msg_len,ULONG msg_prio)79 INT  mq_send( mqd_t mqdes, const CHAR * msg_ptr, size_t msg_len,
80                 ULONG msg_prio )
81 {
82 
83 TX_QUEUE           *Queue;
84 UINT                temp1;
85 POSIX_MSG_QUEUE    *q_ptr;
86 VOID               *bp;
87 UCHAR              *source;
88 UCHAR              *destination;
89 UCHAR              *save_ptr;
90 ULONG               mycount;
91 ULONG               msg[TX_POSIX_MESSAGE_SIZE];
92 
93     /* Assign a temporary variable for clarity.  */
94     Queue = &(mqdes->f_data->queue);
95     q_ptr = (POSIX_MSG_QUEUE * )mqdes->f_data;
96 
97     /* First, check for an invalid queue pointer.  */
98     if ( (!q_ptr) || ( (q_ptr -> px_queue_id) != PX_QUEUE_ID))
99     {
100         /* Queue pointer is invalid, return appropriate error code.  */
101         posix_errno = EBADF;
102         posix_set_pthread_errno(EBADF);
103 
104         /* Return ERROR.  */
105         return(ERROR);
106     }
107     /* Make sure if we're calling this routine from a ISR timeout
108         is set to zero.  */
109     if (!(tx_thread_identify()))
110     {
111         /* POSIX doesn't have error for this, hence give default.  */
112         posix_errno = EINTR ;
113         posix_set_pthread_errno(EINTR);
114 
115         /* Return ERROR.  */
116         return(ERROR);
117     }
118 
119     /* First, check for an invalid queue pointer.  */
120     if ( (!q_ptr) || ( (q_ptr->queue.tx_queue_id) != TX_QUEUE_ID))
121     {
122         /* Queue descriptor is invalid, set appropriate error code.  */
123         posix_errno = EBADF ;
124         posix_set_pthread_errno(EBADF);
125 
126         /* Return ERROR.  */
127         return(ERROR);
128     }
129     if(((mqdes->f_flag & O_WRONLY) != O_WRONLY) && ((mqdes->f_flag & O_RDWR) != O_RDWR))
130     {
131         /* Queue pointer is invalid, return appropriate error code.  */
132         posix_errno = EBADF;
133         posix_set_pthread_errno(EBADF);
134 
135         /* Return ERROR.  */
136         return(ERROR);
137     }
138     if( msg_prio > MQ_PRIO_MAX)
139     {
140         /* Return appropriate error.  */
141         posix_errno = EINVAL;
142         posix_set_pthread_errno(EINVAL);
143 
144         /* Return error.  */
145         return(ERROR);
146     }
147     /* Check for an invalid source for message.  */
148     if (! msg_ptr)
149     {
150         /* POSIX doesn't have error for this, hence give default.  */
151         posix_errno = EINTR ;
152         posix_set_pthread_errno(EINTR);
153 
154         /* Return ERROR.  */
155         return(ERROR);
156     }
157 
158     /* Now check the length of message.  */
159     if ( msg_len > (q_ptr->q_attr.mq_msgsize ) )
160     {
161         /*  Return message length exceeds max length.  */
162         posix_errno = EMSGSIZE ;
163         posix_set_pthread_errno(EMSGSIZE);
164 
165         /* Return ERROR.  */
166         return(ERROR);
167     }
168 
169     /* Now try to allocate memory to save the message from the
170       queue's byte pool.  */
171     temp1 = tx_byte_allocate((TX_BYTE_POOL * )&(q_ptr->vq_message_area), &bp,
172                              msg_len, TX_NO_WAIT);
173 
174     if (temp1 != TX_SUCCESS)
175     {
176     posix_internal_error(9999);
177     }
178     /* Got the memory , Setup source and destination pointers
179        Cast them in UCHAR as message length is in bytes.  */
180     source      =  (UCHAR * ) msg_ptr;
181     destination =  (UCHAR * ) bp;
182 
183     /* Save start of message storage.  */
184     save_ptr   = destination;
185 
186     /* Copy the message into private buffer.  */
187     for ( mycount = 0; mycount < msg_len; mycount++)
188     {
189 
190         * destination++ =  * source++;
191     }
192     /* Restore the pointer of save message.  */
193     source =  save_ptr ;
194     /* Create message that holds saved message pointer and message length.  */
195 #ifdef TX_64_BIT
196     msg[0] = (ULONG)((ALIGN_TYPE)source >> 32);
197     msg[1] = (ULONG)((ALIGN_TYPE)source);
198     msg[2] =  msg_len;
199     msg[3] =  msg_prio;
200     msg[4] =  posix_priority_search(mqdes, msg_prio);
201 #else
202     msg[0] = (ULONG)source;
203     msg[1] =  msg_len;
204     msg[2] =  msg_prio;
205     msg[3] =  posix_priority_search(mqdes, msg_prio);
206 #endif
207     /* Attempt to post the message to the queue.  */
208     temp1 = tx_queue_send(Queue, msg, TX_WAIT_FOREVER);
209     if ( temp1 != TX_SUCCESS)
210     {
211         /* POSIX doesn't have error for this, hence give default.  */
212         posix_errno = EINTR ;
213 	    posix_set_pthread_errno(EINTR);
214 
215         /* Return ERROR.  */
216         return(ERROR);
217     }
218 
219     /* All done.  */
220     return(OK);
221 }
222