[3652ad35] | 1 | /* |
---|
| 2 | * CORE Message Queue Handler |
---|
| 3 | * |
---|
| 4 | * DESCRIPTION: |
---|
| 5 | * |
---|
| 6 | * This package is the implementation of the CORE Message Queue Handler. |
---|
| 7 | * This core object provides task synchronization and communication functions |
---|
| 8 | * via messages passed to queue objects. |
---|
| 9 | * |
---|
| 10 | * COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994. |
---|
| 11 | * On-Line Applications Research Corporation (OAR). |
---|
| 12 | * All rights assigned to U.S. Government, 1994. |
---|
| 13 | * |
---|
| 14 | * This material may be reproduced by or for the U.S. Government pursuant |
---|
| 15 | * to the copyright license under the clause at DFARS 252.227-7013. This |
---|
| 16 | * notice must appear in all copies of this file and its derivatives. |
---|
| 17 | * |
---|
| 18 | * $Id$ |
---|
| 19 | */ |
---|
| 20 | |
---|
| 21 | #include <rtems/system.h> |
---|
| 22 | #include <rtems/rtems/status.h> |
---|
| 23 | #include <rtems/rtems/attr.h> |
---|
| 24 | #include <rtems/core/chain.h> |
---|
| 25 | #include <rtems/core/isr.h> |
---|
| 26 | #include <rtems/rtems/message.h> |
---|
| 27 | #include <rtems/core/object.h> |
---|
| 28 | #include <rtems/rtems/options.h> |
---|
| 29 | #include <rtems/core/states.h> |
---|
| 30 | #include <rtems/rtems/support.h> |
---|
| 31 | #include <rtems/core/thread.h> |
---|
| 32 | #include <rtems/core/wkspace.h> |
---|
| 33 | #include <rtems/core/mpci.h> |
---|
| 34 | #include <rtems/sysstate.h> |
---|
| 35 | |
---|
| 36 | /*PAGE |
---|
| 37 | * |
---|
| 38 | * _CORE_message_queue_Initialize |
---|
| 39 | * |
---|
| 40 | * This routine initializes a newly created message queue based on the |
---|
| 41 | * specified data. |
---|
| 42 | * |
---|
| 43 | * Input parameters: |
---|
| 44 | * the_message_queue - the message queue to initialize |
---|
| 45 | * the_class - the API specific object class |
---|
| 46 | * the_message_queue_attributes - the message queue's attributes |
---|
| 47 | * maximum_pending_messages - maximum message and reserved buffer count |
---|
| 48 | * maximum_message_size - maximum size of each message |
---|
| 49 | * proxy_extract_callout - remote extract support |
---|
| 50 | * |
---|
| 51 | * Output parameters: |
---|
| 52 | * TRUE - if the message queue is initialized |
---|
| 53 | * FALSE - if the message queue is NOT initialized |
---|
| 54 | */ |
---|
| 55 | |
---|
| 56 | boolean _CORE_message_queue_Initialize( |
---|
| 57 | CORE_message_queue_Control *the_message_queue, |
---|
| 58 | Objects_Classes the_class, |
---|
| 59 | CORE_message_queue_Attributes *the_message_queue_attributes, |
---|
| 60 | unsigned32 maximum_pending_messages, |
---|
| 61 | unsigned32 maximum_message_size, |
---|
| 62 | Thread_queue_Extract_callout proxy_extract_callout |
---|
| 63 | ) |
---|
| 64 | { |
---|
| 65 | unsigned32 message_buffering_required; |
---|
| 66 | unsigned32 allocated_message_size; |
---|
| 67 | |
---|
| 68 | the_message_queue->maximum_pending_messages = maximum_pending_messages; |
---|
| 69 | the_message_queue->number_of_pending_messages = 0; |
---|
| 70 | the_message_queue->maximum_message_size = maximum_message_size; |
---|
| 71 | |
---|
| 72 | /* |
---|
| 73 | * round size up to multiple of a ptr for chain init |
---|
| 74 | */ |
---|
| 75 | |
---|
| 76 | allocated_message_size = maximum_message_size; |
---|
| 77 | if (allocated_message_size & (sizeof(unsigned32) - 1)) { |
---|
| 78 | allocated_message_size += sizeof(unsigned32); |
---|
| 79 | allocated_message_size &= ~(sizeof(unsigned32) - 1); |
---|
| 80 | } |
---|
| 81 | |
---|
| 82 | message_buffering_required = maximum_pending_messages * |
---|
| 83 | (allocated_message_size + sizeof(CORE_message_queue_Buffer_control)); |
---|
| 84 | |
---|
| 85 | the_message_queue->message_buffers = (CORE_message_queue_Buffer *) |
---|
| 86 | _Workspace_Allocate( message_buffering_required ); |
---|
| 87 | |
---|
| 88 | if (the_message_queue->message_buffers == 0) |
---|
| 89 | return FALSE; |
---|
| 90 | |
---|
| 91 | _Chain_Initialize ( |
---|
| 92 | &the_message_queue->Inactive_messages, |
---|
| 93 | the_message_queue->message_buffers, |
---|
| 94 | maximum_pending_messages, |
---|
| 95 | allocated_message_size + sizeof( CORE_message_queue_Buffer_control ) |
---|
| 96 | ); |
---|
| 97 | |
---|
| 98 | _Chain_Initialize_empty( &the_message_queue->Pending_messages ); |
---|
| 99 | |
---|
| 100 | _Thread_queue_Initialize( |
---|
| 101 | &the_message_queue->Wait_queue, |
---|
| 102 | the_class, |
---|
| 103 | _CORE_message_queue_Is_priority( the_message_queue_attributes ) ? |
---|
| 104 | THREAD_QUEUE_DISCIPLINE_PRIORITY : THREAD_QUEUE_DISCIPLINE_FIFO, |
---|
| 105 | STATES_WAITING_FOR_MESSAGE, |
---|
| 106 | proxy_extract_callout, |
---|
| 107 | CORE_MESSAGE_QUEUE_STATUS_TIMEOUT |
---|
| 108 | ); |
---|
| 109 | |
---|
| 110 | return TRUE; |
---|
| 111 | } |
---|
| 112 | |
---|
| 113 | /*PAGE |
---|
| 114 | * |
---|
| 115 | * _CORE_message_queue_Close |
---|
| 116 | * |
---|
| 117 | * This function closes a message by returning all allocated space and |
---|
| 118 | * flushing the message_queue's task wait queue. |
---|
| 119 | * |
---|
| 120 | * Input parameters: |
---|
| 121 | * the_message_queue - the message_queue to be flushed |
---|
| 122 | * remote_extract_callout - function to invoke remotely |
---|
| 123 | * status - status to pass to thread |
---|
| 124 | * |
---|
| 125 | * Output parameters: NONE |
---|
| 126 | */ |
---|
| 127 | |
---|
| 128 | void _CORE_message_queue_Close( |
---|
| 129 | CORE_message_queue_Control *the_message_queue, |
---|
| 130 | Thread_queue_Flush_callout remote_extract_callout, |
---|
| 131 | unsigned32 status |
---|
| 132 | ) |
---|
| 133 | { |
---|
| 134 | |
---|
| 135 | if ( the_message_queue->number_of_pending_messages != 0 ) |
---|
| 136 | (void) _CORE_message_queue_Flush_support( the_message_queue ); |
---|
| 137 | else |
---|
| 138 | _Thread_queue_Flush( |
---|
| 139 | &the_message_queue->Wait_queue, |
---|
| 140 | remote_extract_callout, |
---|
| 141 | status |
---|
| 142 | ); |
---|
| 143 | |
---|
| 144 | (void) _Workspace_Free( the_message_queue->message_buffers ); |
---|
| 145 | |
---|
| 146 | } |
---|
| 147 | |
---|
| 148 | /*PAGE |
---|
| 149 | * |
---|
| 150 | * _CORE_message_queue_Flush |
---|
| 151 | * |
---|
| 152 | * This function flushes the message_queue's task wait queue. The number |
---|
| 153 | * of messages flushed from the queue is returned. |
---|
| 154 | * |
---|
| 155 | * Input parameters: |
---|
| 156 | * the_message_queue - the message_queue to be flushed |
---|
| 157 | * |
---|
| 158 | * Output parameters: |
---|
| 159 | * returns - the number of messages flushed from the queue |
---|
| 160 | */ |
---|
| 161 | |
---|
| 162 | unsigned32 _CORE_message_queue_Flush( |
---|
| 163 | CORE_message_queue_Control *the_message_queue |
---|
| 164 | ) |
---|
| 165 | { |
---|
| 166 | if ( the_message_queue->number_of_pending_messages != 0 ) |
---|
| 167 | return _CORE_message_queue_Flush_support( the_message_queue ); |
---|
| 168 | else |
---|
| 169 | return 0; |
---|
| 170 | } |
---|
| 171 | |
---|
| 172 | /*PAGE |
---|
| 173 | * |
---|
| 174 | * _CORE_message_queue_Broadcast |
---|
| 175 | * |
---|
| 176 | * This function sends a message for every thread waiting on the queue and |
---|
| 177 | * returns the number of threads made ready by the message. |
---|
| 178 | * |
---|
| 179 | * Input parameters: |
---|
| 180 | * the_message_queue - message is submitted to this message queue |
---|
| 181 | * buffer - pointer to message buffer |
---|
| 182 | * size - size in bytes of message to send |
---|
| 183 | * id - id of message queue |
---|
| 184 | * api_message_queue_mp_support - api specific mp support callout |
---|
| 185 | * count - area to store number of threads made ready |
---|
| 186 | * |
---|
| 187 | * Output parameters: |
---|
| 188 | * count - number of threads made ready |
---|
| 189 | * CORE_MESSAGE_QUEUE_SUCCESSFUL - if successful |
---|
| 190 | * error code - if unsuccessful |
---|
| 191 | */ |
---|
| 192 | |
---|
| 193 | CORE_message_queue_Status _CORE_message_queue_Broadcast( |
---|
| 194 | CORE_message_queue_Control *the_message_queue, |
---|
| 195 | void *buffer, |
---|
| 196 | unsigned32 size, |
---|
| 197 | Objects_Id id, |
---|
| 198 | CORE_message_queue_API_mp_support_callout api_message_queue_mp_support, |
---|
| 199 | unsigned32 *count |
---|
| 200 | ) |
---|
| 201 | { |
---|
| 202 | Thread_Control *the_thread; |
---|
| 203 | unsigned32 number_broadcasted; |
---|
| 204 | Thread_Wait_information *waitp; |
---|
| 205 | unsigned32 constrained_size; |
---|
| 206 | |
---|
| 207 | number_broadcasted = 0; |
---|
| 208 | while ((the_thread = _Thread_queue_Dequeue(&the_message_queue->Wait_queue))) { |
---|
| 209 | waitp = &the_thread->Wait; |
---|
| 210 | number_broadcasted += 1; |
---|
| 211 | |
---|
| 212 | constrained_size = size; |
---|
| 213 | if ( size > the_message_queue->maximum_message_size ) |
---|
| 214 | constrained_size = the_message_queue->maximum_message_size; |
---|
| 215 | |
---|
| 216 | _CORE_message_queue_Copy_buffer( |
---|
| 217 | buffer, |
---|
| 218 | waitp->return_argument, |
---|
| 219 | constrained_size |
---|
| 220 | ); |
---|
| 221 | |
---|
| 222 | *(rtems_unsigned32 *)the_thread->Wait.return_argument_1 = size; |
---|
| 223 | |
---|
| 224 | if ( !_Objects_Is_local_id( the_thread->Object.id ) ) |
---|
| 225 | (*api_message_queue_mp_support) ( the_thread, id ); |
---|
| 226 | |
---|
| 227 | } |
---|
| 228 | *count = number_broadcasted; |
---|
| 229 | return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; |
---|
| 230 | } |
---|
| 231 | |
---|
| 232 | /*PAGE |
---|
| 233 | * |
---|
| 234 | * _CORE_message_queue_Seize |
---|
| 235 | * |
---|
| 236 | * This kernel routine dequeues a message, copies the message buffer to |
---|
| 237 | * a given destination buffer, and frees the message buffer to the |
---|
| 238 | * inactive message pool. The thread will be blocked if wait is TRUE, |
---|
| 239 | * otherwise an error will be given to the thread if no messages are available. |
---|
| 240 | * |
---|
| 241 | * Input parameters: |
---|
| 242 | * the_message_queue - pointer to message queue |
---|
| 243 | * id - id of object we are waitig on |
---|
| 244 | * buffer - pointer to message buffer to be filled |
---|
| 245 | * size - pointer to the size of buffer to be filled |
---|
| 246 | * wait - TRUE if wait is allowed, FALSE otherwise |
---|
| 247 | * timeout - time to wait for a message |
---|
| 248 | * |
---|
| 249 | * Output parameters: NONE |
---|
| 250 | * |
---|
| 251 | * NOTE: Dependent on BUFFER_LENGTH |
---|
| 252 | * |
---|
| 253 | * INTERRUPT LATENCY: |
---|
| 254 | * available |
---|
| 255 | * wait |
---|
| 256 | */ |
---|
| 257 | |
---|
| 258 | void _CORE_message_queue_Seize( |
---|
| 259 | CORE_message_queue_Control *the_message_queue, |
---|
| 260 | Objects_Id id, |
---|
| 261 | void *buffer, |
---|
| 262 | unsigned32 *size, |
---|
| 263 | boolean wait, |
---|
| 264 | Watchdog_Interval timeout |
---|
| 265 | ) |
---|
| 266 | { |
---|
| 267 | ISR_Level level; |
---|
| 268 | CORE_message_queue_Buffer_control *the_message; |
---|
| 269 | Thread_Control *executing; |
---|
| 270 | |
---|
| 271 | executing = _Thread_Executing; |
---|
| 272 | executing->Wait.return_code = CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; |
---|
| 273 | _ISR_Disable( level ); |
---|
| 274 | if ( the_message_queue->number_of_pending_messages != 0 ) { |
---|
| 275 | the_message_queue->number_of_pending_messages -= 1; |
---|
| 276 | |
---|
| 277 | the_message = _CORE_message_queue_Get_pending_message( the_message_queue ); |
---|
| 278 | _ISR_Enable( level ); |
---|
| 279 | *size = the_message->Contents.size; |
---|
| 280 | _CORE_message_queue_Copy_buffer(the_message->Contents.buffer,buffer,*size ); |
---|
| 281 | _CORE_message_queue_Free_message_buffer(the_message_queue, the_message ); |
---|
| 282 | return; |
---|
| 283 | } |
---|
| 284 | |
---|
| 285 | if ( !wait ) { |
---|
| 286 | _ISR_Enable( level ); |
---|
| 287 | executing->Wait.return_code = CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_NOWAIT; |
---|
| 288 | return; |
---|
| 289 | } |
---|
| 290 | |
---|
| 291 | the_message_queue->Wait_queue.sync = TRUE; |
---|
| 292 | executing->Wait.queue = &the_message_queue->Wait_queue; |
---|
| 293 | executing->Wait.id = id; |
---|
| 294 | executing->Wait.return_argument = (void *)buffer; |
---|
| 295 | executing->Wait.return_argument_1 = (void *)size; |
---|
| 296 | _ISR_Enable( level ); |
---|
| 297 | |
---|
| 298 | _Thread_queue_Enqueue( &the_message_queue->Wait_queue, timeout ); |
---|
| 299 | } |
---|
| 300 | |
---|
| 301 | /*PAGE |
---|
| 302 | * |
---|
| 303 | * _CORE_message_queue_Flush_support |
---|
| 304 | * |
---|
| 305 | * This message handler routine removes all messages from a message queue |
---|
| 306 | * and returns them to the inactive message pool. The number of messages |
---|
| 307 | * flushed from the queue is returned |
---|
| 308 | * |
---|
| 309 | * Input parameters: |
---|
| 310 | * the_message_queue - pointer to message queue |
---|
| 311 | * |
---|
| 312 | * Output parameters: |
---|
| 313 | * returns - number of messages placed on inactive chain |
---|
| 314 | * |
---|
| 315 | * INTERRUPT LATENCY: |
---|
| 316 | * only case |
---|
| 317 | */ |
---|
| 318 | |
---|
| 319 | unsigned32 _CORE_message_queue_Flush_support( |
---|
| 320 | CORE_message_queue_Control *the_message_queue |
---|
| 321 | ) |
---|
| 322 | { |
---|
| 323 | ISR_Level level; |
---|
| 324 | Chain_Node *inactive_first; |
---|
| 325 | Chain_Node *message_queue_first; |
---|
| 326 | Chain_Node *message_queue_last; |
---|
| 327 | unsigned32 count; |
---|
| 328 | |
---|
| 329 | _ISR_Disable( level ); |
---|
| 330 | inactive_first = the_message_queue->Inactive_messages.first; |
---|
| 331 | message_queue_first = the_message_queue->Pending_messages.first; |
---|
| 332 | message_queue_last = the_message_queue->Pending_messages.last; |
---|
| 333 | |
---|
| 334 | the_message_queue->Inactive_messages.first = message_queue_first; |
---|
| 335 | message_queue_last->next = inactive_first; |
---|
| 336 | inactive_first->previous = message_queue_last; |
---|
| 337 | message_queue_first->previous = |
---|
| 338 | _Chain_Head( &the_message_queue->Inactive_messages ); |
---|
| 339 | |
---|
| 340 | _Chain_Initialize_empty( &the_message_queue->Pending_messages ); |
---|
| 341 | |
---|
| 342 | count = the_message_queue->number_of_pending_messages; |
---|
| 343 | the_message_queue->number_of_pending_messages = 0; |
---|
| 344 | _ISR_Enable( level ); |
---|
| 345 | return count; |
---|
| 346 | } |
---|
| 347 | |
---|
| 348 | /*PAGE |
---|
| 349 | * |
---|
| 350 | * _CORE_message_queue_Submit |
---|
| 351 | * |
---|
| 352 | * This routine implements the send and urgent message functions. It |
---|
| 353 | * processes a message that is to be submitted to the designated |
---|
| 354 | * message queue. The message will either be processed as a |
---|
| 355 | * send message which it will be inserted at the rear of the queue |
---|
| 356 | * or it will be processed as an urgent message which will be inserted |
---|
| 357 | * at the front of the queue. |
---|
| 358 | * |
---|
| 359 | * Input parameters: |
---|
| 360 | * the_message_queue - message is submitted to this message queue |
---|
| 361 | * buffer - pointer to message buffer |
---|
| 362 | * size - size in bytes of message to send |
---|
| 363 | * id - id of message queue |
---|
| 364 | * api_message_queue_mp_support - api specific mp support callout |
---|
| 365 | * submit_type - send or urgent message |
---|
| 366 | * |
---|
| 367 | * Output parameters: |
---|
| 368 | * CORE_MESSAGE_QUEUE_SUCCESSFUL - if successful |
---|
| 369 | * error code - if unsuccessful |
---|
| 370 | */ |
---|
| 371 | |
---|
| 372 | CORE_message_queue_Status _CORE_message_queue_Submit( |
---|
| 373 | CORE_message_queue_Control *the_message_queue, |
---|
| 374 | void *buffer, |
---|
| 375 | unsigned32 size, |
---|
| 376 | Objects_Id id, |
---|
| 377 | CORE_message_queue_API_mp_support_callout api_message_queue_mp_support, |
---|
| 378 | CORE_message_queue_Submit_types submit_type |
---|
| 379 | ) |
---|
| 380 | { |
---|
| 381 | CORE_message_queue_Buffer_control *the_message; |
---|
| 382 | Thread_Control *the_thread; |
---|
| 383 | |
---|
| 384 | if ( size > the_message_queue->maximum_message_size ) |
---|
| 385 | return CORE_MESSAGE_QUEUE_STATUS_INVALID_SIZE; |
---|
| 386 | |
---|
| 387 | /* |
---|
| 388 | * Is there a thread currently waiting on this message queue? |
---|
| 389 | */ |
---|
| 390 | |
---|
| 391 | the_thread = _Thread_queue_Dequeue( &the_message_queue->Wait_queue ); |
---|
| 392 | if ( the_thread ) |
---|
| 393 | { |
---|
| 394 | _CORE_message_queue_Copy_buffer( |
---|
| 395 | buffer, |
---|
| 396 | the_thread->Wait.return_argument, |
---|
| 397 | size |
---|
| 398 | ); |
---|
| 399 | *(rtems_unsigned32 *)the_thread->Wait.return_argument_1 = size; |
---|
| 400 | |
---|
| 401 | if ( !_Objects_Is_local_id( the_thread->Object.id ) ) |
---|
| 402 | (*api_message_queue_mp_support) ( the_thread, id ); |
---|
| 403 | |
---|
| 404 | return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; |
---|
| 405 | } |
---|
| 406 | |
---|
| 407 | /* |
---|
| 408 | * No one waiting on this one currently. |
---|
| 409 | * Allocate a message buffer and store it away |
---|
| 410 | */ |
---|
| 411 | |
---|
| 412 | if ( the_message_queue->number_of_pending_messages == |
---|
| 413 | the_message_queue->maximum_pending_messages ) { |
---|
| 414 | return CORE_MESSAGE_QUEUE_STATUS_TOO_MANY; |
---|
| 415 | } |
---|
| 416 | |
---|
| 417 | the_message = _CORE_message_queue_Allocate_message_buffer(the_message_queue); |
---|
| 418 | if ( the_message == 0) |
---|
| 419 | return CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED; |
---|
| 420 | |
---|
| 421 | _CORE_message_queue_Copy_buffer( buffer, the_message->Contents.buffer, size ); |
---|
| 422 | the_message->Contents.size = size; |
---|
| 423 | |
---|
| 424 | the_message_queue->number_of_pending_messages += 1; |
---|
| 425 | |
---|
| 426 | switch ( submit_type ) { |
---|
| 427 | case CORE_MESSAGE_QUEUE_SEND_REQUEST: |
---|
| 428 | _CORE_message_queue_Append( the_message_queue, the_message ); |
---|
| 429 | break; |
---|
| 430 | case CORE_MESSAGE_QUEUE_URGENT_REQUEST: |
---|
| 431 | _CORE_message_queue_Prepend( the_message_queue, the_message ); |
---|
| 432 | break; |
---|
| 433 | } |
---|
| 434 | |
---|
| 435 | return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL; |
---|
| 436 | } |
---|