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