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