FreeCalypso > hg > ffs-editor
comparison src/nucleus/quc.c @ 0:92470e5d0b9e
src: partial import from FC Selenite
| author | Mychaela Falconia <falcon@freecalypso.org> |
|---|---|
| date | Fri, 15 May 2020 01:28:16 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:92470e5d0b9e |
|---|---|
| 1 /*************************************************************************/ | |
| 2 /* */ | |
| 3 /* Copyright Mentor Graphics Corporation 2002 */ | |
| 4 /* All Rights Reserved. */ | |
| 5 /* */ | |
| 6 /* THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS */ | |
| 7 /* THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS */ | |
| 8 /* SUBJECT TO LICENSE TERMS. */ | |
| 9 /* */ | |
| 10 /*************************************************************************/ | |
| 11 | |
| 12 /*************************************************************************/ | |
| 13 /* */ | |
| 14 /* FILE NAME VERSION */ | |
| 15 /* */ | |
| 16 /* quc.c Nucleus PLUS 1.14 */ | |
| 17 /* */ | |
| 18 /* COMPONENT */ | |
| 19 /* */ | |
| 20 /* QU - Queue Management */ | |
| 21 /* */ | |
| 22 /* DESCRIPTION */ | |
| 23 /* */ | |
| 24 /* This file contains the core routines for the Queue management */ | |
| 25 /* component. */ | |
| 26 /* */ | |
| 27 /* DATA STRUCTURES */ | |
| 28 /* */ | |
| 29 /* None */ | |
| 30 /* */ | |
| 31 /* FUNCTIONS */ | |
| 32 /* */ | |
| 33 /* QUC_Create_Queue Create a message queue */ | |
| 34 /* QUC_Delete_Queue Delete a message queue */ | |
| 35 /* QUC_Send_To_Queue Send message to a queue */ | |
| 36 /* QUC_Receive_From_Queue Receive a message from queue */ | |
| 37 /* QUC_Cleanup Cleanup on timeout or a */ | |
| 38 /* terminate condition */ | |
| 39 /* */ | |
| 40 /* DEPENDENCIES */ | |
| 41 /* */ | |
| 42 /* cs_extr.h Common Service functions */ | |
| 43 /* tc_extr.h Thread Control functions */ | |
| 44 /* qu_extr.h Queue functions */ | |
| 45 /* hi_extr.h History functions */ | |
| 46 /* */ | |
| 47 /* HISTORY */ | |
| 48 /* */ | |
| 49 /* DATE REMARKS */ | |
| 50 /* */ | |
| 51 /* 03-01-1993 Created initial version 1.0 */ | |
| 52 /* 04-19-1993 Verified version 1.0 */ | |
| 53 /* 08-09-1993 Corrected pointer retrieval */ | |
| 54 /* loop, resulting in version 1.0a */ | |
| 55 /* 08-09-1993 Verified version 1.0a */ | |
| 56 /* 11-01-1993 Corrected a problem with fixed- */ | |
| 57 /* size queues of a size equal to */ | |
| 58 /* one message, resulting in */ | |
| 59 /* version 1.0b */ | |
| 60 /* 11-01-1993 Verified version 1.0b */ | |
| 61 /* 03-01-1994 Moved non-core functions into */ | |
| 62 /* supplemental files, changed */ | |
| 63 /* function interfaces to match */ | |
| 64 /* those in prototype, added */ | |
| 65 /* register options, changed */ | |
| 66 /* protection logic to reduce */ | |
| 67 /* overhead, corrected bug in */ | |
| 68 /* queue reset, optimized item */ | |
| 69 /* copy loops, resulting in */ | |
| 70 /* version 1.1 */ | |
| 71 /* */ | |
| 72 /* 03-18-1994 Verified version 1.1 */ | |
| 73 /* 04-17-1996 updated to version 1.2 */ | |
| 74 /* 01-28-1998 Corrected SPR412 resulting in */ | |
| 75 /* version 1.2a. */ | |
| 76 /* 03-24-1998 Released version 1.3 */ | |
| 77 /* 03-26-1999 Released 1.11m (new release */ | |
| 78 /* numbering scheme) */ | |
| 79 /* 04-17-2002 Released version 1.13m */ | |
| 80 /* 11-07-2002 Released version 1.14 */ | |
| 81 /*************************************************************************/ | |
| 82 #define NU_SOURCE_FILE | |
| 83 | |
| 84 | |
| 85 #include "cs_extr.h" /* Common service functions */ | |
| 86 #include "tc_extr.h" /* Thread control functions */ | |
| 87 #include "qu_extr.h" /* Queue functions */ | |
| 88 #include "hi_extr.h" /* History functions */ | |
| 89 | |
| 90 | |
| 91 /* Define external inner-component global data references. */ | |
| 92 | |
| 93 extern CS_NODE *QUD_Created_Queues_List; | |
| 94 extern UNSIGNED QUD_Total_Queues; | |
| 95 extern TC_PROTECT QUD_List_Protect; | |
| 96 | |
| 97 | |
| 98 /* Define internal component function prototypes. */ | |
| 99 | |
| 100 VOID QUC_Cleanup(VOID *information); | |
| 101 | |
| 102 | |
| 103 /*************************************************************************/ | |
| 104 /* */ | |
| 105 /* FUNCTION */ | |
| 106 /* */ | |
| 107 /* QUC_Create_Queue */ | |
| 108 /* */ | |
| 109 /* DESCRIPTION */ | |
| 110 /* */ | |
| 111 /* This function creates a queue and then places it on the list */ | |
| 112 /* of created queues. */ | |
| 113 /* */ | |
| 114 /* CALLED BY */ | |
| 115 /* */ | |
| 116 /* Application */ | |
| 117 /* QUCE_Create_Queue Error checking shell */ | |
| 118 /* */ | |
| 119 /* CALLS */ | |
| 120 /* */ | |
| 121 /* CSC_Place_On_List Add node to linked-list */ | |
| 122 /* [HIC_Make_History_Entry] Make entry in history log */ | |
| 123 /* [TCT_Check_Stack] Stack checking function */ | |
| 124 /* TCT_Protect Protect created list */ | |
| 125 /* TCT_Unprotect Un-protect data structure */ | |
| 126 /* */ | |
| 127 /* INPUTS */ | |
| 128 /* */ | |
| 129 /* queue_ptr Queue control block pointer */ | |
| 130 /* name Queue name */ | |
| 131 /* start_address Starting address of actual */ | |
| 132 /* queue area */ | |
| 133 /* queue_size Total size of queue */ | |
| 134 /* message_type Type of message supported by */ | |
| 135 /* the queue (fixed/variable) */ | |
| 136 /* message_size Size of message. Variable */ | |
| 137 /* message-length queues, this*/ | |
| 138 /* represents the maximum size*/ | |
| 139 /* suspend_type Suspension type */ | |
| 140 /* */ | |
| 141 /* OUTPUTS */ | |
| 142 /* */ | |
| 143 /* NU_SUCCESS */ | |
| 144 /* */ | |
| 145 /* HISTORY */ | |
| 146 /* */ | |
| 147 /* DATE REMARKS */ | |
| 148 /* */ | |
| 149 /* 03-01-1993 Created initial version 1.0 */ | |
| 150 /* 04-19-1993 Verified version 1.0 */ | |
| 151 /* 03-01-1994 Changed function interfaces to */ | |
| 152 /* match those in prototype, */ | |
| 153 /* added register options, */ | |
| 154 /* resulting in version 1.1 */ | |
| 155 /* */ | |
| 156 /* 03-18-1994 Verified version 1.1 */ | |
| 157 /* */ | |
| 158 /*************************************************************************/ | |
| 159 STATUS QUC_Create_Queue(NU_QUEUE *queue_ptr, CHAR *name, | |
| 160 VOID *start_address, UNSIGNED queue_size, | |
| 161 OPTION message_type, UNSIGNED message_size, | |
| 162 OPTION suspend_type) | |
| 163 { | |
| 164 | |
| 165 R1 QU_QCB *queue; /* Queue control block ptr */ | |
| 166 INT i; /* Working index variable */ | |
| 167 NU_SUPERV_USER_VARIABLES | |
| 168 | |
| 169 /* Switch to supervisor mode */ | |
| 170 NU_SUPERVISOR_MODE(); | |
| 171 | |
| 172 /* Move input queue pointer into internal pointer. */ | |
| 173 queue = (QU_QCB *) queue_ptr; | |
| 174 | |
| 175 | |
| 176 #ifdef NU_ENABLE_STACK_CHECK | |
| 177 | |
| 178 /* Call stack checking function to check for an overflow condition. */ | |
| 179 TCT_Check_Stack(); | |
| 180 | |
| 181 #endif | |
| 182 | |
| 183 #ifdef NU_ENABLE_HISTORY | |
| 184 | |
| 185 /* Make an entry that corresponds to this function in the system history | |
| 186 log. */ | |
| 187 HIC_Make_History_Entry(NU_CREATE_QUEUE_ID, (UNSIGNED) queue, | |
| 188 (UNSIGNED) name, (UNSIGNED) start_address); | |
| 189 | |
| 190 #endif | |
| 191 | |
| 192 /* First, clear the queue ID just in case it is an old Queue | |
| 193 Control Block. */ | |
| 194 queue -> qu_id = 0; | |
| 195 | |
| 196 /* Fill in the queue name. */ | |
| 197 for (i = 0; i < NU_MAX_NAME; i++) | |
| 198 queue -> qu_name[i] = name[i]; | |
| 199 | |
| 200 /* Setup the queue suspension type. */ | |
| 201 if (suspend_type == NU_FIFO) | |
| 202 | |
| 203 /* FIFO suspension is selected, setup the flag accordingly. */ | |
| 204 queue -> qu_fifo_suspend = NU_TRUE; | |
| 205 | |
| 206 else | |
| 207 | |
| 208 /* Priority suspension is selected. */ | |
| 209 queue -> qu_fifo_suspend = NU_FALSE; | |
| 210 | |
| 211 /* Setup the queue message type. */ | |
| 212 if (message_type == NU_FIXED_SIZE) | |
| 213 | |
| 214 /* Fixed-size messages are required. */ | |
| 215 queue -> qu_fixed_size = NU_TRUE; | |
| 216 else | |
| 217 | |
| 218 /* Variable-size messages are required. */ | |
| 219 queue -> qu_fixed_size = NU_FALSE; | |
| 220 | |
| 221 /* Setup the message size. */ | |
| 222 queue -> qu_message_size = message_size; | |
| 223 | |
| 224 /* Clear the messages counter. */ | |
| 225 queue -> qu_messages = 0; | |
| 226 | |
| 227 /* Setup the actual queue parameters. */ | |
| 228 queue -> qu_queue_size = queue_size; | |
| 229 | |
| 230 /* If the queue supports fixed-size messages, make sure that the queue | |
| 231 size is an even multiple of the message size. */ | |
| 232 if (queue -> qu_fixed_size) | |
| 233 | |
| 234 /* Adjust the area of the queue being used. */ | |
| 235 queue_size = (queue_size / message_size) * message_size; | |
| 236 | |
| 237 queue -> qu_available = queue_size; | |
| 238 queue -> qu_start = (UNSIGNED *) start_address; | |
| 239 queue -> qu_end = queue -> qu_start + queue_size; | |
| 240 queue -> qu_read = (UNSIGNED *) start_address; | |
| 241 queue -> qu_write = (UNSIGNED *) start_address; | |
| 242 | |
| 243 /* Clear the suspension list pointer. */ | |
| 244 queue -> qu_suspension_list = NU_NULL; | |
| 245 | |
| 246 /* Clear the number of tasks waiting on the queue counter. */ | |
| 247 queue -> qu_tasks_waiting = 0; | |
| 248 | |
| 249 /* Clear the urgent message list pointer. */ | |
| 250 queue -> qu_urgent_list = NU_NULL; | |
| 251 | |
| 252 /* Initialize link pointers. */ | |
| 253 queue -> qu_created.cs_previous = NU_NULL; | |
| 254 queue -> qu_created.cs_next = NU_NULL; | |
| 255 | |
| 256 /* Protect against access to the list of created queues. */ | |
| 257 TCT_Protect(&QUD_List_Protect); | |
| 258 | |
| 259 /* At this point the queue is completely built. The ID can now be | |
| 260 set and it can be linked into the created queue list. */ | |
| 261 queue -> qu_id = QU_QUEUE_ID; | |
| 262 | |
| 263 /* Link the queue into the list of created queues and increment the | |
| 264 total number of queues in the system. */ | |
| 265 CSC_Place_On_List(&QUD_Created_Queues_List, &(queue -> qu_created)); | |
| 266 QUD_Total_Queues++; | |
| 267 | |
| 268 #ifdef INCLUDE_PROVIEW | |
| 269 _RTProf_DumpQueue(RT_PROF_CREATE_QUEUE,queue,RT_PROF_OK); | |
| 270 #endif | |
| 271 | |
| 272 /* Release protection against access to the list of created queues. */ | |
| 273 TCT_Unprotect(); | |
| 274 | |
| 275 /* Return to user mode */ | |
| 276 NU_USER_MODE(); | |
| 277 | |
| 278 /* Return successful completion. */ | |
| 279 return(NU_SUCCESS); | |
| 280 } | |
| 281 | |
| 282 | |
| 283 /*************************************************************************/ | |
| 284 /* */ | |
| 285 /* FUNCTION */ | |
| 286 /* */ | |
| 287 /* QUC_Delete_Queue */ | |
| 288 /* */ | |
| 289 /* DESCRIPTION */ | |
| 290 /* */ | |
| 291 /* This function deletes a queue and removes it from the list of */ | |
| 292 /* created queues. All tasks suspended on the queue are */ | |
| 293 /* resumed. Note that this function does not free the memory */ | |
| 294 /* associated with the queue. */ | |
| 295 /* */ | |
| 296 /* CALLED BY */ | |
| 297 /* */ | |
| 298 /* Application */ | |
| 299 /* QUCE_Delete_Queue Error checking shell */ | |
| 300 /* */ | |
| 301 /* CALLS */ | |
| 302 /* */ | |
| 303 /* CSC_Remove_From_List Remove node from list */ | |
| 304 /* [HIC_Make_History_Entry] Make entry in history log */ | |
| 305 /* TCC_Resume_Task Resume a suspended task */ | |
| 306 /* [TCT_Check_Stack] Stack checking function */ | |
| 307 /* TCT_Control_To_System Transfer control to system */ | |
| 308 /* TCT_Protect Protect created list */ | |
| 309 /* TCT_Set_Current_Protect Setup current protect pointer*/ | |
| 310 /* TCT_System_Protect Protect against system access*/ | |
| 311 /* TCT_System_Unprotect Release system protection */ | |
| 312 /* TCT_Unprotect Release protection */ | |
| 313 /* */ | |
| 314 /* INPUTS */ | |
| 315 /* */ | |
| 316 /* queue_ptr Queue control block pointer */ | |
| 317 /* */ | |
| 318 /* OUTPUTS */ | |
| 319 /* */ | |
| 320 /* NU_SUCCESS */ | |
| 321 /* */ | |
| 322 /* HISTORY */ | |
| 323 /* */ | |
| 324 /* DATE REMARKS */ | |
| 325 /* */ | |
| 326 /* 03-01-1993 Created initial version 1.0 */ | |
| 327 /* 04-19-1993 Verified version 1.0 */ | |
| 328 /* 03-01-1994 Changed function interfaces to */ | |
| 329 /* match those in prototype, */ | |
| 330 /* added register options, changed */ | |
| 331 /* protection logic to reduce */ | |
| 332 /* overhead, resulting in */ | |
| 333 /* version 1.1 */ | |
| 334 /* */ | |
| 335 /* 03-18-1994 Verified version 1.1 */ | |
| 336 /* */ | |
| 337 /*************************************************************************/ | |
| 338 STATUS QUC_Delete_Queue(NU_QUEUE *queue_ptr) | |
| 339 { | |
| 340 | |
| 341 R1 QU_QCB *queue; /* Queue control block ptr */ | |
| 342 QU_SUSPEND *suspend_ptr; /* Suspend block pointer */ | |
| 343 QU_SUSPEND *next_ptr; /* Next suspend block pointer*/ | |
| 344 STATUS preempt; /* Status for resume call */ | |
| 345 NU_SUPERV_USER_VARIABLES | |
| 346 | |
| 347 /* Move input queue pointer into internal pointer. */ | |
| 348 queue = (QU_QCB *) queue_ptr; | |
| 349 | |
| 350 /* Switch to supervisor mode */ | |
| 351 NU_SUPERVISOR_MODE(); | |
| 352 | |
| 353 #ifdef NU_ENABLE_STACK_CHECK | |
| 354 | |
| 355 /* Call stack checking function to check for an overflow condition. */ | |
| 356 TCT_Check_Stack(); | |
| 357 | |
| 358 #endif | |
| 359 | |
| 360 #ifdef NU_ENABLE_HISTORY | |
| 361 | |
| 362 /* Make an entry that corresponds to this function in the system history | |
| 363 log. */ | |
| 364 HIC_Make_History_Entry(NU_DELETE_QUEUE_ID, (UNSIGNED) queue, | |
| 365 (UNSIGNED) 0, (UNSIGNED) 0); | |
| 366 | |
| 367 #endif | |
| 368 | |
| 369 /* Protect against access to the queue. */ | |
| 370 TCT_System_Protect(); | |
| 371 | |
| 372 #ifdef INCLUDE_PROVIEW | |
| 373 _RTProf_DumpQueue(RT_PROF_DELETE_QUEUE,queue,RT_PROF_OK); | |
| 374 #endif | |
| 375 | |
| 376 /* Clear the queue ID. */ | |
| 377 queue -> qu_id = 0; | |
| 378 | |
| 379 /* Release protection. */ | |
| 380 TCT_Unprotect(); | |
| 381 | |
| 382 /* Protect against access to the list of created queues. */ | |
| 383 TCT_Protect(&QUD_List_Protect); | |
| 384 | |
| 385 /* Remove the queue from the list of created queues. */ | |
| 386 CSC_Remove_From_List(&QUD_Created_Queues_List, &(queue -> qu_created)); | |
| 387 | |
| 388 /* Decrement the total number of created queues. */ | |
| 389 QUD_Total_Queues--; | |
| 390 | |
| 391 /* Pickup the suspended task pointer list. */ | |
| 392 suspend_ptr = queue -> qu_suspension_list; | |
| 393 | |
| 394 /* Walk the chain task(s) currently suspended on the queue. */ | |
| 395 preempt = 0; | |
| 396 while (suspend_ptr) | |
| 397 { | |
| 398 | |
| 399 /* Protect against system access. */ | |
| 400 TCT_System_Protect(); | |
| 401 | |
| 402 /* Resume the suspended task. Insure that the status returned is | |
| 403 NU_QUEUE_DELETED. */ | |
| 404 suspend_ptr -> qu_return_status = NU_QUEUE_DELETED; | |
| 405 | |
| 406 /* Point to the next suspend structure in the link. */ | |
| 407 next_ptr = (QU_SUSPEND *) (suspend_ptr -> qu_suspend_link.cs_next); | |
| 408 | |
| 409 /* Resume the specified task. */ | |
| 410 preempt = preempt | | |
| 411 TCC_Resume_Task((NU_TASK *) suspend_ptr -> qu_suspended_task, | |
| 412 NU_QUEUE_SUSPEND); | |
| 413 | |
| 414 /* Determine if the next is the same as the head pointer. */ | |
| 415 if (next_ptr == queue -> qu_suspension_list) | |
| 416 | |
| 417 /* Clear the suspension pointer to signal the end of the list | |
| 418 traversal. */ | |
| 419 suspend_ptr = NU_NULL; | |
| 420 else | |
| 421 | |
| 422 /* Position suspend pointer to the next pointer. */ | |
| 423 suspend_ptr = next_ptr; | |
| 424 | |
| 425 /* Modify current protection. */ | |
| 426 TCT_Set_Current_Protect(&QUD_List_Protect); | |
| 427 | |
| 428 /* Clear the system protection. */ | |
| 429 TCT_System_Unprotect(); | |
| 430 } | |
| 431 | |
| 432 /* Pickup the urgent message suspension list. */ | |
| 433 suspend_ptr = queue -> qu_urgent_list; | |
| 434 | |
| 435 /* Walk the chain task(s) currently suspended on the queue. */ | |
| 436 while (suspend_ptr) | |
| 437 { | |
| 438 | |
| 439 /* Protect against system access. */ | |
| 440 TCT_System_Protect(); | |
| 441 | |
| 442 /* Resume the suspended task. Insure that the status returned is | |
| 443 NU_QUEUE_DELETED. */ | |
| 444 suspend_ptr -> qu_return_status = NU_QUEUE_DELETED; | |
| 445 | |
| 446 /* Point to the next suspend structure in the link. */ | |
| 447 next_ptr = (QU_SUSPEND *) (suspend_ptr -> qu_suspend_link.cs_next); | |
| 448 | |
| 449 /* Resume the specified task. */ | |
| 450 preempt = preempt | | |
| 451 TCC_Resume_Task((NU_TASK *) suspend_ptr -> qu_suspended_task, | |
| 452 NU_QUEUE_SUSPEND); | |
| 453 | |
| 454 /* Determine if the next is the same as the head pointer. */ | |
| 455 if (next_ptr == queue -> qu_urgent_list) | |
| 456 | |
| 457 /* Clear the suspension pointer to signal the end of the list | |
| 458 traversal. */ | |
| 459 suspend_ptr = NU_NULL; | |
| 460 else | |
| 461 | |
| 462 /* Position to the next suspend block in the list. */ | |
| 463 suspend_ptr = next_ptr; | |
| 464 | |
| 465 /* Modify current protection. */ | |
| 466 TCT_Set_Current_Protect(&QUD_List_Protect); | |
| 467 | |
| 468 /* Clear the system protection. */ | |
| 469 TCT_System_Unprotect(); | |
| 470 } | |
| 471 | |
| 472 /* Determine if preemption needs to occur. */ | |
| 473 if (preempt) | |
| 474 | |
| 475 /* Transfer control to system to facilitate preemption. */ | |
| 476 TCT_Control_To_System(); | |
| 477 | |
| 478 /* Release protection against access to the list of created queues. */ | |
| 479 TCT_Unprotect(); | |
| 480 | |
| 481 /* Return to user mode */ | |
| 482 NU_USER_MODE(); | |
| 483 | |
| 484 /* Return a successful completion. */ | |
| 485 return(NU_SUCCESS); | |
| 486 } | |
| 487 | |
| 488 | |
| 489 /*************************************************************************/ | |
| 490 /* */ | |
| 491 /* FUNCTION */ | |
| 492 /* */ | |
| 493 /* QUC_Send_To_Queue */ | |
| 494 /* */ | |
| 495 /* DESCRIPTION */ | |
| 496 /* */ | |
| 497 /* This function sends a message to the specified queue. The */ | |
| 498 /* message length is determined by the caller. If there are one */ | |
| 499 /* or more tasks suspended on the queue for a message, the message */ | |
| 500 /* is copied into the message area of the first waiting task. If */ | |
| 501 /* the task's request is satisfied, it is resumed. Otherwise, if */ | |
| 502 /* the queue cannot hold the message, suspension of the calling */ | |
| 503 /* task is an option of the caller. */ | |
| 504 /* */ | |
| 505 /* CALLED BY */ | |
| 506 /* */ | |
| 507 /* Application */ | |
| 508 /* QUCE_Send_To_Queue Error checking shell */ | |
| 509 /* */ | |
| 510 /* CALLS */ | |
| 511 /* */ | |
| 512 /* CSC_Place_On_List Place on suspend list */ | |
| 513 /* CSC_Priority_Place_On_List Place on priority list */ | |
| 514 /* CSC_Remove_From_List Remove from suspend list */ | |
| 515 /* [HIC_Make_History_Entry] Make entry in history log */ | |
| 516 /* TCC_Resume_Task Resume a suspended task */ | |
| 517 /* TCC_Suspend_Task Suspend calling task */ | |
| 518 /* TCC_Task_Priority Pickup task's priority */ | |
| 519 /* [TCT_Check_Stack] Stack checking function */ | |
| 520 /* TCT_Control_To_System Transfer control to system */ | |
| 521 /* TCT_Current_Thread Pickup current thread pointer*/ | |
| 522 /* TCT_System_Protect Protect queue */ | |
| 523 /* TCT_Unprotect Release protection */ | |
| 524 /* */ | |
| 525 /* INPUTS */ | |
| 526 /* */ | |
| 527 /* queue_ptr Queue control block pointer */ | |
| 528 /* message Pointer to message to send */ | |
| 529 /* size Size of message to send */ | |
| 530 /* suspend Suspension option if full */ | |
| 531 /* */ | |
| 532 /* OUTPUTS */ | |
| 533 /* */ | |
| 534 /* NU_SUCCESS If service is successful */ | |
| 535 /* NU_QUEUE_FULL If queue is currently full */ | |
| 536 /* NU_TIMEOUT If timeout on service expires*/ | |
| 537 /* NU_QUEUE_DELETED If queue was deleted during */ | |
| 538 /* suspension */ | |
| 539 /* NU_QUEUE_RESET If queue was reset during */ | |
| 540 /* suspension */ | |
| 541 /* */ | |
| 542 /* HISTORY */ | |
| 543 /* */ | |
| 544 /* DATE REMARKS */ | |
| 545 /* */ | |
| 546 /* 03-01-1993 Created initial version 1.0 */ | |
| 547 /* 04-19-1993 Verified version 1.0 */ | |
| 548 /* 03-01-1994 Changed function interfaces to */ | |
| 549 /* match those in prototype, */ | |
| 550 /* added register options, changed */ | |
| 551 /* protection logic to reduce */ | |
| 552 /* overhead, optimized copy loop, */ | |
| 553 /* resulting in version 1.1 */ | |
| 554 /* */ | |
| 555 /* 03-18-1994 Verified version 1.1 */ | |
| 556 /* */ | |
| 557 /*************************************************************************/ | |
| 558 STATUS QUC_Send_To_Queue(NU_QUEUE *queue_ptr, VOID *message, UNSIGNED size, | |
| 559 UNSIGNED suspend) | |
| 560 { | |
| 561 | |
| 562 R1 QU_QCB *queue; /* Queue control block ptr */ | |
| 563 QU_SUSPEND suspend_block; /* Allocate suspension block */ | |
| 564 QU_SUSPEND *suspend_ptr; /* Pointer to suspend block */ | |
| 565 R3 UNSIGNED_PTR source; /* Pointer to source */ | |
| 566 R4 UNSIGNED_PTR destination; /* Pointer to destination */ | |
| 567 UNSIGNED copy_size; /* Partial copy size */ | |
| 568 R2 INT i; /* Working counter */ | |
| 569 TC_TCB *task; /* Task pointer */ | |
| 570 STATUS preempt; /* Preempt flag */ | |
| 571 STATUS status; /* Completion status */ | |
| 572 NU_SUPERV_USER_VARIABLES | |
| 573 | |
| 574 /* Switch to supervisor mode */ | |
| 575 NU_SUPERVISOR_MODE(); | |
| 576 | |
| 577 /* Move input queue pointer into internal pointer. */ | |
| 578 queue = (QU_QCB *) queue_ptr; | |
| 579 | |
| 580 | |
| 581 #ifdef NU_ENABLE_STACK_CHECK | |
| 582 | |
| 583 /* Call stack checking function to check for an overflow condition. */ | |
| 584 TCT_Check_Stack(); | |
| 585 | |
| 586 #endif | |
| 587 | |
| 588 #ifdef NU_ENABLE_HISTORY | |
| 589 | |
| 590 /* Make an entry that corresponds to this function in the system history | |
| 591 log. */ | |
| 592 HIC_Make_History_Entry(NU_SEND_TO_QUEUE_ID, (UNSIGNED) queue, | |
| 593 (UNSIGNED) message, (UNSIGNED) size); | |
| 594 | |
| 595 #endif | |
| 596 | |
| 597 /* Initialize the status as successful. */ | |
| 598 status = NU_SUCCESS; | |
| 599 | |
| 600 /* Protect against simultaneous access to the queue. */ | |
| 601 TCT_System_Protect(); | |
| 602 | |
| 603 /* Determine if an extra word of overhead needs to be added to the | |
| 604 calculation. */ | |
| 605 if (queue -> qu_fixed_size) | |
| 606 | |
| 607 /* No overhead. */ | |
| 608 i = 0; | |
| 609 else | |
| 610 { | |
| 611 /* Variable messages have one additional word of overhead. */ | |
| 612 i = 1; | |
| 613 | |
| 614 /* Make special check to see if a suspension needs to be | |
| 615 forced for a variable length message. */ | |
| 616 if ((queue -> qu_suspension_list) && (queue -> qu_messages)) | |
| 617 { | |
| 618 | |
| 619 /* Pickup task control block pointer. */ | |
| 620 task = (TC_TCB *) TCT_Current_Thread(); | |
| 621 | |
| 622 /* Now we know that there are other task(s) are suspended trying | |
| 623 to send a variable length message. Determine whether or not | |
| 624 a suspension should be forced. */ | |
| 625 if ((queue -> qu_fifo_suspend) || | |
| 626 (suspend == NU_NO_SUSPEND) || | |
| 627 ((queue -> qu_suspension_list) -> qu_suspend_link.cs_priority <= | |
| 628 TCC_Task_Priority(task))) | |
| 629 | |
| 630 /* Bump the computed size to avoid placing the new variable | |
| 631 length message ahead of the suspended tasks. */ | |
| 632 i = (INT) queue -> qu_available; | |
| 633 } | |
| 634 } | |
| 635 | |
| 636 /* Determine if there is enough room in the queue for the message. The | |
| 637 extra logic is to prevent a variable-length message from sn*/ | |
| 638 if (queue -> qu_available < (size + i)) | |
| 639 { | |
| 640 | |
| 641 /* Queue does not have room for the message. Determine if | |
| 642 suspension is required. */ | |
| 643 if (suspend) | |
| 644 { | |
| 645 | |
| 646 /* Suspension is requested. */ | |
| 647 | |
| 648 /* Increment the number of tasks waiting. */ | |
| 649 queue -> qu_tasks_waiting++; | |
| 650 | |
| 651 #ifdef INCLUDE_PROVIEW | |
| 652 _RTProf_DumpQueue(RT_PROF_SEND_TO_QUEUE,queue,RT_PROF_WAIT); | |
| 653 #endif | |
| 654 | |
| 655 /* Setup the suspend block and suspend the calling task. */ | |
| 656 suspend_ptr = &suspend_block; | |
| 657 suspend_ptr -> qu_queue = queue; | |
| 658 suspend_ptr -> qu_suspend_link.cs_next = NU_NULL; | |
| 659 suspend_ptr -> qu_suspend_link.cs_previous = NU_NULL; | |
| 660 suspend_ptr -> qu_message_area = (UNSIGNED_PTR) message; | |
| 661 suspend_ptr -> qu_message_size = size; | |
| 662 task = (TC_TCB *) TCT_Current_Thread(); | |
| 663 suspend_ptr -> qu_suspended_task = task; | |
| 664 | |
| 665 /* Determine if priority or FIFO suspension is associated with the | |
| 666 queue. */ | |
| 667 if (queue -> qu_fifo_suspend) | |
| 668 { | |
| 669 | |
| 670 /* FIFO suspension is required. Link the suspend block into | |
| 671 the list of suspended tasks on this queue. */ | |
| 672 CSC_Place_On_List((CS_NODE **) &(queue -> qu_suspension_list), | |
| 673 &(suspend_ptr -> qu_suspend_link)); | |
| 674 } | |
| 675 else | |
| 676 { | |
| 677 | |
| 678 /* Get the priority of the current thread so the suspend block | |
| 679 can be placed in the appropriate place. */ | |
| 680 suspend_ptr -> qu_suspend_link.cs_priority = | |
| 681 TCC_Task_Priority(task); | |
| 682 | |
| 683 CSC_Priority_Place_On_List((CS_NODE **) | |
| 684 &(queue -> qu_suspension_list), | |
| 685 &(suspend_ptr -> qu_suspend_link)); | |
| 686 } | |
| 687 | |
| 688 /* Finally, suspend the calling task. Note that the suspension call | |
| 689 automatically clears the protection on the queue. */ | |
| 690 TCC_Suspend_Task((NU_TASK *) task, NU_QUEUE_SUSPEND, | |
| 691 QUC_Cleanup, suspend_ptr, suspend); | |
| 692 | |
| 693 /* Pickup the return status. */ | |
| 694 status = suspend_ptr -> qu_return_status; | |
| 695 } | |
| 696 else | |
| 697 { | |
| 698 | |
| 699 /* Return a status of NU_QUEUE_FULL because there is no | |
| 700 room in the queue for the message. */ | |
| 701 status = NU_QUEUE_FULL; | |
| 702 | |
| 703 #ifdef INCLUDE_PROVIEW | |
| 704 _RTProf_DumpQueue(RT_PROF_SEND_TO_QUEUE,queue,RT_PROF_FAIL); | |
| 705 #endif | |
| 706 | |
| 707 } | |
| 708 } | |
| 709 else | |
| 710 { | |
| 711 | |
| 712 /* Determine if a task is waiting on an empty queue. */ | |
| 713 if ((queue -> qu_suspension_list) && (queue -> qu_messages == 0)) | |
| 714 { | |
| 715 | |
| 716 /* Task is waiting on an empty queue for a message. */ | |
| 717 | |
| 718 /* Decrement the number of tasks waiting on queue. */ | |
| 719 queue -> qu_tasks_waiting--; | |
| 720 | |
| 721 #ifdef INCLUDE_PROVIEW | |
| 722 _RTProf_DumpQueue(RT_PROF_SEND_TO_QUEUE,queue,RT_PROF_OK); | |
| 723 #endif | |
| 724 | |
| 725 /* Remove the first suspended block from the list. */ | |
| 726 suspend_ptr = queue -> qu_suspension_list; | |
| 727 CSC_Remove_From_List((CS_NODE **) &(queue -> qu_suspension_list), | |
| 728 &(suspend_ptr -> qu_suspend_link)); | |
| 729 | |
| 730 /* Setup the source and destination pointers. */ | |
| 731 source = (UNSIGNED_PTR) message; | |
| 732 destination = suspend_ptr -> qu_message_area; | |
| 733 | |
| 734 /* Initialize the return status. */ | |
| 735 suspend_ptr -> qu_return_status = NU_SUCCESS; | |
| 736 | |
| 737 /* Loop to actually copy the message. */ | |
| 738 i = (INT) size; | |
| 739 do | |
| 740 { | |
| 741 *(destination++) = *(source); | |
| 742 if ((--i) == 0) | |
| 743 break; | |
| 744 source++; | |
| 745 } while (1); | |
| 746 | |
| 747 /* Return the size of the message copied. */ | |
| 748 suspend_ptr -> qu_actual_size = size; | |
| 749 | |
| 750 /* Wakeup the waiting task and check for preemption. */ | |
| 751 preempt = | |
| 752 TCC_Resume_Task((NU_TASK *) suspend_ptr -> qu_suspended_task, | |
| 753 NU_QUEUE_SUSPEND); | |
| 754 | |
| 755 /* Determine if preemption needs to take place. */ | |
| 756 if (preempt) | |
| 757 | |
| 758 /* Transfer control to the system if the resumed task function | |
| 759 detects a preemption condition. */ | |
| 760 TCT_Control_To_System(); | |
| 761 } | |
| 762 else | |
| 763 { | |
| 764 | |
| 765 /* There is enough room in the queue and no task is waiting. */ | |
| 766 | |
| 767 /* Setup the source pointer. */ | |
| 768 source = (UNSIGNED_PTR) message; | |
| 769 destination = queue -> qu_write; | |
| 770 | |
| 771 /* Process according to the type of message supported. */ | |
| 772 if (queue -> qu_fixed_size) | |
| 773 { | |
| 774 | |
| 775 /* Fixed-size messages are supported by this queue. */ | |
| 776 | |
| 777 /* Loop to copy the message into the queue area. */ | |
| 778 i = (INT) size; | |
| 779 do | |
| 780 { | |
| 781 *(destination++) = *(source); | |
| 782 if ((--i) == 0) | |
| 783 break; | |
| 784 source++; | |
| 785 } while (1); | |
| 786 } | |
| 787 else | |
| 788 { | |
| 789 | |
| 790 /* Variable-size messages are supported. Processing must | |
| 791 check for queue wrap-around conditions. */ | |
| 792 | |
| 793 /* Place message size in first location. */ | |
| 794 *(destination++) = size; | |
| 795 | |
| 796 /* Check for a wrap-around condition on the queue. */ | |
| 797 if (destination >= queue -> qu_end) | |
| 798 | |
| 799 /* Wrap the write pointer back to the top of the queue | |
| 800 area. */ | |
| 801 destination = queue -> qu_start; | |
| 802 | |
| 803 /* Decrement the number of words remaining by 1 for this | |
| 804 extra word of overhead. */ | |
| 805 queue -> qu_available--; | |
| 806 | |
| 807 /* Calculate the number of words remaining from the write | |
| 808 pointer to the bottom of the queue. */ | |
| 809 copy_size = queue -> qu_end - destination; | |
| 810 | |
| 811 /* Determine if the message needs to be wrapped around the | |
| 812 edge of the queue area. */ | |
| 813 if (copy_size >= size) | |
| 814 { | |
| 815 | |
| 816 /* Copy the whole message at once. */ | |
| 817 i = (INT) size; | |
| 818 do | |
| 819 { | |
| 820 *(destination++) = *(source); | |
| 821 if ((--i) == 0) | |
| 822 break; | |
| 823 source++; | |
| 824 } while (1); | |
| 825 } | |
| 826 else | |
| 827 { | |
| 828 | |
| 829 /* Copy the first half of the message. */ | |
| 830 i = (INT) copy_size; | |
| 831 do | |
| 832 { | |
| 833 *(destination) = *(source++); | |
| 834 if ((--i) == 0) | |
| 835 break; | |
| 836 destination++; | |
| 837 } while (1); | |
| 838 | |
| 839 /* Copy the second half of the message. */ | |
| 840 destination = queue -> qu_start; | |
| 841 i = (INT) (size - copy_size); | |
| 842 do | |
| 843 { | |
| 844 *(destination++) = *(source); | |
| 845 if ((--i) == 0) | |
| 846 break; | |
| 847 source++; | |
| 848 } while (1); | |
| 849 } | |
| 850 } | |
| 851 | |
| 852 /* Check again for wrap-around condition on the write pointer. */ | |
| 853 if (destination >= queue -> qu_end) | |
| 854 | |
| 855 /* Move the write pointer to the top of the queue area. */ | |
| 856 queue -> qu_write = queue -> qu_start; | |
| 857 else | |
| 858 | |
| 859 /* Simply copy the last position of the destination pointer | |
| 860 into the write pointer. */ | |
| 861 queue -> qu_write = destination; | |
| 862 | |
| 863 /* Decrement the number of available words. */ | |
| 864 queue -> qu_available = queue -> qu_available - size; | |
| 865 | |
| 866 /* Increment the number of messages in the queue. */ | |
| 867 queue -> qu_messages++; | |
| 868 | |
| 869 #ifdef INCLUDE_PROVIEW | |
| 870 _RTProf_DumpQueue(RT_PROF_SEND_TO_QUEUE,queue,RT_PROF_OK); | |
| 871 #endif | |
| 872 | |
| 873 } | |
| 874 } | |
| 875 | |
| 876 /* Release protection against access to the queue. */ | |
| 877 TCT_Unprotect(); | |
| 878 | |
| 879 /* Return to user mode */ | |
| 880 NU_USER_MODE(); | |
| 881 | |
| 882 /* Return the completion status. */ | |
| 883 return(status); | |
| 884 } | |
| 885 | |
| 886 | |
| 887 /*************************************************************************/ | |
| 888 /* */ | |
| 889 /* FUNCTION */ | |
| 890 /* */ | |
| 891 /* QUC_Receive_From_Queue */ | |
| 892 /* */ | |
| 893 /* DESCRIPTION */ | |
| 894 /* */ | |
| 895 /* This function receives a message from the specified queue. The */ | |
| 896 /* size of the message is specified by the caller. If there is a */ | |
| 897 /* message currently in the queue, the message is removed from the */ | |
| 898 /* queue and placed in the caller's area. Suspension is possible */ | |
| 899 /* if the request cannot be satisfied. */ | |
| 900 /* */ | |
| 901 /* CALLED BY */ | |
| 902 /* */ | |
| 903 /* Application */ | |
| 904 /* QUCE_Receive_From_Queue Error checking shell */ | |
| 905 /* */ | |
| 906 /* CALLS */ | |
| 907 /* */ | |
| 908 /* CSC_Place_On_List Place on suspend list */ | |
| 909 /* CSC_Priority_Place_On_List Place on priority list */ | |
| 910 /* CSC_Remove_From_List Remove from suspend list */ | |
| 911 /* [HIC_Make_History_Entry] Make entry in history log */ | |
| 912 /* TCC_Resume_Task Resume a suspended task */ | |
| 913 /* TCC_Suspend_Task Suspend calling task */ | |
| 914 /* TCC_Task_Priority Pickup task's priority */ | |
| 915 /* [TCT_Check_Stack] Stack checking function */ | |
| 916 /* TCT_Control_To_System Transfer control to system */ | |
| 917 /* TCT_Current_Thread Pickup current thread pointer*/ | |
| 918 /* TCT_System_Protect Protect queue */ | |
| 919 /* TCT_Unprotect Release protection */ | |
| 920 /* */ | |
| 921 /* INPUTS */ | |
| 922 /* */ | |
| 923 /* queue_ptr Queue control block pointer */ | |
| 924 /* message Pointer to message to send */ | |
| 925 /* size Size of the message */ | |
| 926 /* actual_size Size of message received */ | |
| 927 /* suspend Suspension option if empty */ | |
| 928 /* */ | |
| 929 /* OUTPUTS */ | |
| 930 /* */ | |
| 931 /* NU_SUCCESS If service is successful */ | |
| 932 /* NU_QUEUE_EMPTY If queue is currently empty */ | |
| 933 /* NU_TIMEOUT If timeout on service expires*/ | |
| 934 /* NU_QUEUE_DELETED If queue was deleted during */ | |
| 935 /* suspension */ | |
| 936 /* NU_QUEUE_RESET If queue was reset during */ | |
| 937 /* suspension */ | |
| 938 /* */ | |
| 939 /* HISTORY */ | |
| 940 /* */ | |
| 941 /* DATE REMARKS */ | |
| 942 /* */ | |
| 943 /* 03-01-1993 Created initial version 1.0 */ | |
| 944 /* 04-19-1993 Verified version 1.0 */ | |
| 945 /* 11-01-1993 Corrected a problem resuming a */ | |
| 946 /* task suspended on a full queue */ | |
| 947 /* that only has a capacity of a */ | |
| 948 /* single message, resulting in */ | |
| 949 /* version 1.0b */ | |
| 950 /* 11-01-1993 Verified version 1.0b */ | |
| 951 /* 03-01-1994 Changed function interfaces to */ | |
| 952 /* match those in prototype, */ | |
| 953 /* added register options, changed */ | |
| 954 /* protection logic to reduce */ | |
| 955 /* overhead, optimized copy loop, */ | |
| 956 /* resulting in version 1.1 */ | |
| 957 /* */ | |
| 958 /* 03-18-1994 Verified version 1.1 */ | |
| 959 /* 01-28-1998 Corrected SPR412. */ | |
| 960 /* */ | |
| 961 /*************************************************************************/ | |
| 962 STATUS QUC_Receive_From_Queue(NU_QUEUE *queue_ptr, VOID *message, | |
| 963 UNSIGNED size, UNSIGNED *actual_size, UNSIGNED suspend) | |
| 964 { | |
| 965 | |
| 966 R1 QU_QCB *queue; /* Queue control block ptr */ | |
| 967 QU_SUSPEND suspend_block; /* Allocate suspension block */ | |
| 968 QU_SUSPEND *suspend_ptr; /* Pointer to suspend block */ | |
| 969 R3 UNSIGNED_PTR source; /* Pointer to source */ | |
| 970 R4 UNSIGNED_PTR destination; /* Pointer to destination */ | |
| 971 TC_TCB *task; /* Task pointer */ | |
| 972 UNSIGNED copy_size; /* Number of words to copy */ | |
| 973 R2 INT i; /* Working counter */ | |
| 974 STATUS preempt; /* Preemption flag */ | |
| 975 STATUS status; /* Completion status */ | |
| 976 NU_SUPERV_USER_VARIABLES | |
| 977 | |
| 978 | |
| 979 /* Move input queue pointer into internal pointer. */ | |
| 980 queue = (QU_QCB *) queue_ptr; | |
| 981 | |
| 982 /* Switch to supervisor mode */ | |
| 983 NU_SUPERVISOR_MODE(); | |
| 984 | |
| 985 #ifdef NU_ENABLE_STACK_CHECK | |
| 986 | |
| 987 /* Call stack checking function to check for an overflow condition. */ | |
| 988 TCT_Check_Stack(); | |
| 989 | |
| 990 #endif | |
| 991 | |
| 992 #ifdef NU_ENABLE_HISTORY | |
| 993 | |
| 994 /* Make an entry that corresponds to this function in the system history | |
| 995 log. */ | |
| 996 HIC_Make_History_Entry(NU_RECEIVE_FROM_QUEUE_ID, (UNSIGNED) queue, | |
| 997 (UNSIGNED) message, (UNSIGNED) size); | |
| 998 | |
| 999 #endif | |
| 1000 | |
| 1001 /* Initialize the status as successful. */ | |
| 1002 status = NU_SUCCESS; | |
| 1003 | |
| 1004 /* Protect against simultaneous access to the queue. */ | |
| 1005 TCT_System_Protect(); | |
| 1006 | |
| 1007 /* Determine if an urgent message request is currently suspended. */ | |
| 1008 if (queue -> qu_urgent_list) | |
| 1009 { | |
| 1010 | |
| 1011 /* If so, copy the message from the suspended request block and | |
| 1012 resume the associated task. */ | |
| 1013 | |
| 1014 /* Decrement the number of tasks waiting on queue. */ | |
| 1015 queue -> qu_tasks_waiting--; | |
| 1016 | |
| 1017 /* Remove the first suspended block from the list. */ | |
| 1018 suspend_ptr = queue -> qu_urgent_list; | |
| 1019 CSC_Remove_From_List((CS_NODE **) &(queue -> qu_urgent_list), | |
| 1020 &(suspend_ptr -> qu_suspend_link)); | |
| 1021 | |
| 1022 /* Setup the source and destination pointers. */ | |
| 1023 destination = (UNSIGNED_PTR) message; | |
| 1024 source = suspend_ptr -> qu_message_area; | |
| 1025 | |
| 1026 /* Initialize the return status. */ | |
| 1027 suspend_ptr -> qu_return_status = NU_SUCCESS; | |
| 1028 | |
| 1029 /* Loop to actually copy the message. */ | |
| 1030 i = (INT) suspend_ptr -> qu_message_size; | |
| 1031 do | |
| 1032 { | |
| 1033 *(destination++) = *(source); | |
| 1034 if ((--i) == 0) | |
| 1035 break; | |
| 1036 source++; | |
| 1037 } while (1); | |
| 1038 | |
| 1039 /* Return the size of the message copied. */ | |
| 1040 *actual_size = suspend_ptr -> qu_message_size; | |
| 1041 | |
| 1042 /* Wakeup the waiting task and check for preemption. */ | |
| 1043 preempt = | |
| 1044 TCC_Resume_Task((NU_TASK *) suspend_ptr -> qu_suspended_task, | |
| 1045 NU_QUEUE_SUSPEND); | |
| 1046 | |
| 1047 /* Determine if preemption needs to take place. */ | |
| 1048 if (preempt) | |
| 1049 | |
| 1050 /* Transfer control to the system if the resumed task function | |
| 1051 detects a preemption condition. */ | |
| 1052 TCT_Control_To_System(); | |
| 1053 } | |
| 1054 | |
| 1055 /* Determine if there are messages in the queue. */ | |
| 1056 else if (queue -> qu_messages) | |
| 1057 { | |
| 1058 | |
| 1059 /* Copy message from queue into the caller's area. */ | |
| 1060 | |
| 1061 /* Setup the source and destination pointers. */ | |
| 1062 source = queue -> qu_read; | |
| 1063 destination = (UNSIGNED_PTR) message; | |
| 1064 | |
| 1065 /* Process according to the type of message supported by the queue. */ | |
| 1066 if (queue -> qu_fixed_size) | |
| 1067 { | |
| 1068 | |
| 1069 /* Queue supports fixed-size messages. */ | |
| 1070 | |
| 1071 /* Copy the message from the queue area into the destination. */ | |
| 1072 i = (INT) size; | |
| 1073 do | |
| 1074 { | |
| 1075 *(destination) = *(source++); | |
| 1076 if ((--i) == 0) | |
| 1077 break; | |
| 1078 destination++; | |
| 1079 } while (1); | |
| 1080 } | |
| 1081 else | |
| 1082 { | |
| 1083 | |
| 1084 /* Queue supports variable-size messages. */ | |
| 1085 | |
| 1086 /* Variable length message size is actually in the queue area. */ | |
| 1087 size = *(source++); | |
| 1088 | |
| 1089 /* Check for a wrap-around condition on the queue. */ | |
| 1090 if (source >= queue -> qu_end) | |
| 1091 | |
| 1092 /* Wrap the read pointer back to the top of the queue | |
| 1093 area. */ | |
| 1094 source = queue -> qu_start; | |
| 1095 | |
| 1096 /* Increment the number of available words in the queue. */ | |
| 1097 queue -> qu_available++; | |
| 1098 | |
| 1099 /* Calculate the number of words remaining from the read pointer | |
| 1100 to the bottom of the queue. */ | |
| 1101 copy_size = queue -> qu_end - source; | |
| 1102 | |
| 1103 /* Determine if the message needs to be wrapped around the | |
| 1104 edge of the queue area. */ | |
| 1105 if (copy_size >= size) | |
| 1106 { | |
| 1107 | |
| 1108 /* Copy the whole message at once. */ | |
| 1109 i = (INT) size; | |
| 1110 do | |
| 1111 { | |
| 1112 *(destination) = *(source++); | |
| 1113 if ((--i) == 0) | |
| 1114 break; | |
| 1115 destination++; | |
| 1116 } while (1); | |
| 1117 } | |
| 1118 else | |
| 1119 { | |
| 1120 | |
| 1121 /* Copy the first half of the message. */ | |
| 1122 i = (INT) copy_size; | |
| 1123 do | |
| 1124 { | |
| 1125 *(destination++) = *(source); | |
| 1126 if ((--i) == 0) | |
| 1127 break; | |
| 1128 source++; | |
| 1129 } while (1); | |
| 1130 | |
| 1131 /* Copy the second half of the message. */ | |
| 1132 source = queue -> qu_start; | |
| 1133 i = (INT) (size - copy_size); | |
| 1134 do | |
| 1135 { | |
| 1136 *(destination) = *(source++); | |
| 1137 if ((--i) == 0) | |
| 1138 break; | |
| 1139 destination++; | |
| 1140 } while (1); | |
| 1141 } | |
| 1142 } | |
| 1143 | |
| 1144 /* Check again for wrap-around condition on the read pointer. */ | |
| 1145 if (source >= queue -> qu_end) | |
| 1146 | |
| 1147 /* Move the read pointer to the top of the queue area. */ | |
| 1148 queue -> qu_read = queue -> qu_start; | |
| 1149 else | |
| 1150 | |
| 1151 /* Move the read pointer to where the copy left off. */ | |
| 1152 queue -> qu_read = source; | |
| 1153 | |
| 1154 /* Increment the number of available words. */ | |
| 1155 queue -> qu_available = queue -> qu_available + size; | |
| 1156 | |
| 1157 /* Decrement the number of messages in the queue. */ | |
| 1158 queue -> qu_messages--; | |
| 1159 | |
| 1160 /* Return the number of words received. */ | |
| 1161 *actual_size = size; | |
| 1162 | |
| 1163 #ifdef INCLUDE_PROVIEW | |
| 1164 _RTProf_DumpQueue(RT_PROF_RECEIVE_FROM_QUEUE,queue,RT_PROF_OK); | |
| 1165 #endif | |
| 1166 | |
| 1167 /* Determine if any tasks suspended on a full queue can be woken | |
| 1168 up. */ | |
| 1169 if (queue -> qu_suspension_list) | |
| 1170 { | |
| 1171 | |
| 1172 /* Overhead of each queue message. */ | |
| 1173 if (!queue -> qu_fixed_size) | |
| 1174 | |
| 1175 i = 1; | |
| 1176 else | |
| 1177 | |
| 1178 i = 0; | |
| 1179 | |
| 1180 /* Pickup the suspension list and examine suspension blocks | |
| 1181 to see if the message could now fit in the queue. */ | |
| 1182 suspend_ptr = queue -> qu_suspension_list; | |
| 1183 preempt = NU_FALSE; | |
| 1184 while ((suspend_ptr) && | |
| 1185 ((suspend_ptr -> qu_message_size + i) <= queue -> qu_available)) | |
| 1186 { | |
| 1187 | |
| 1188 /* Place the suspended task's message into the queue. */ | |
| 1189 | |
| 1190 /* Setup the source and destination pointers. */ | |
| 1191 source = suspend_ptr -> qu_message_area; | |
| 1192 destination = queue -> qu_write; | |
| 1193 size = suspend_ptr -> qu_message_size; | |
| 1194 | |
| 1195 /* Process according to the type of message supported. */ | |
| 1196 if (queue -> qu_fixed_size) | |
| 1197 { | |
| 1198 | |
| 1199 /* Fixed-size messages are supported by this queue. */ | |
| 1200 | |
| 1201 /* Loop to copy the message into the queue area. */ | |
| 1202 i = (INT) size; | |
| 1203 do | |
| 1204 { | |
| 1205 *(destination++) = *(source); | |
| 1206 if ((--i) == 0) | |
| 1207 break; | |
| 1208 source++; | |
| 1209 } while (1); | |
| 1210 } | |
| 1211 else | |
| 1212 { | |
| 1213 | |
| 1214 /* Variable-size messages are supported. Processing must | |
| 1215 check for queue wrap-around conditions. */ | |
| 1216 | |
| 1217 /* Place message size in first location. */ | |
| 1218 *(destination++) = size; | |
| 1219 | |
| 1220 /* Check for a wrap-around condition on the queue. */ | |
| 1221 if (destination >= queue -> qu_end) | |
| 1222 | |
| 1223 /* Wrap the write pointer back to the top of the queue | |
| 1224 area. */ | |
| 1225 destination = queue -> qu_start; | |
| 1226 | |
| 1227 /* Decrement the number of words remaining by 1 for this | |
| 1228 extra word of overhead. */ | |
| 1229 queue -> qu_available--; | |
| 1230 | |
| 1231 /* Calculate the number of words remaining from the write | |
| 1232 pointer to the bottom of the queue. */ | |
| 1233 copy_size = queue -> qu_end - destination; | |
| 1234 | |
| 1235 /* Determine if the message needs to be wrapped around the | |
| 1236 edge of the queue area. */ | |
| 1237 if (copy_size >= size) | |
| 1238 { | |
| 1239 | |
| 1240 /* Copy the whole message at once. */ | |
| 1241 i = (INT) size; | |
| 1242 do | |
| 1243 { | |
| 1244 *(destination++) = *(source); | |
| 1245 if ((--i) == 0) | |
| 1246 break; | |
| 1247 source++; | |
| 1248 } while(1); | |
| 1249 } | |
| 1250 else | |
| 1251 { | |
| 1252 | |
| 1253 /* Copy the first half of the message. */ | |
| 1254 i = (INT) copy_size; | |
| 1255 do | |
| 1256 { | |
| 1257 *(destination) = *(source++); | |
| 1258 if ((--i) == 0) | |
| 1259 break; | |
| 1260 destination++; | |
| 1261 } while (1); | |
| 1262 | |
| 1263 /* Copy the second half of the message. */ | |
| 1264 destination = queue -> qu_start; | |
| 1265 i = (INT) (size - copy_size); | |
| 1266 do | |
| 1267 { | |
| 1268 *(destination++) = *(source); | |
| 1269 if ((--i) == 0) | |
| 1270 break; | |
| 1271 source++; | |
| 1272 } while (1); | |
| 1273 } | |
| 1274 } | |
| 1275 | |
| 1276 /* Check again for wrap-around condition on the write | |
| 1277 pointer. */ | |
| 1278 if (destination >= queue -> qu_end) | |
| 1279 | |
| 1280 /* Move the write pointer to the top of the queue area. */ | |
| 1281 queue -> qu_write = queue -> qu_start; | |
| 1282 else | |
| 1283 | |
| 1284 /* Simply copy the last position of the destination pointer | |
| 1285 into the write pointer. */ | |
| 1286 queue -> qu_write = destination; | |
| 1287 | |
| 1288 /* Decrement the number of available words. */ | |
| 1289 queue -> qu_available = queue -> qu_available - size; | |
| 1290 | |
| 1291 /* Increment the number of messages in the queue. */ | |
| 1292 queue -> qu_messages++; | |
| 1293 | |
| 1294 /* Decrement the number of tasks waiting counter. */ | |
| 1295 queue -> qu_tasks_waiting--; | |
| 1296 | |
| 1297 /* Remove the first suspended block from the list. */ | |
| 1298 CSC_Remove_From_List((CS_NODE **) | |
| 1299 &(queue -> qu_suspension_list), | |
| 1300 &(suspend_ptr -> qu_suspend_link)); | |
| 1301 | |
| 1302 /* Return a successful status. */ | |
| 1303 suspend_ptr -> qu_return_status = NU_SUCCESS; | |
| 1304 | |
| 1305 /* Resume the suspended task. */ | |
| 1306 preempt = preempt | | |
| 1307 TCC_Resume_Task((NU_TASK *) suspend_ptr -> qu_suspended_task, | |
| 1308 NU_QUEUE_SUSPEND); | |
| 1309 | |
| 1310 /* Setup suspend pointer to the head of the list. */ | |
| 1311 suspend_ptr = queue -> qu_suspension_list; | |
| 1312 | |
| 1313 /* Overhead of each queue message. */ | |
| 1314 if (!queue -> qu_fixed_size) | |
| 1315 | |
| 1316 i = 1; | |
| 1317 else | |
| 1318 | |
| 1319 i = 0; | |
| 1320 } | |
| 1321 | |
| 1322 /* Determine if a preempt condition is present. */ | |
| 1323 if (preempt) | |
| 1324 | |
| 1325 /* Transfer control to the system if the resumed task function | |
| 1326 detects a preemption condition. */ | |
| 1327 TCT_Control_To_System(); | |
| 1328 } | |
| 1329 } | |
| 1330 else | |
| 1331 { | |
| 1332 | |
| 1333 /* Queue is empty. Determine if the task wants to suspend. */ | |
| 1334 if (suspend) | |
| 1335 { | |
| 1336 | |
| 1337 /* Increment the number of tasks waiting on the queue counter. */ | |
| 1338 queue -> qu_tasks_waiting++; | |
| 1339 | |
| 1340 #ifdef INCLUDE_PROVIEW | |
| 1341 _RTProf_DumpQueue(RT_PROF_RECEIVE_FROM_QUEUE,queue,RT_PROF_WAIT); | |
| 1342 #endif | |
| 1343 | |
| 1344 /* Setup the suspend block and suspend the calling task. */ | |
| 1345 suspend_ptr = &suspend_block; | |
| 1346 suspend_ptr -> qu_queue = queue; | |
| 1347 suspend_ptr -> qu_suspend_link.cs_next = NU_NULL; | |
| 1348 suspend_ptr -> qu_suspend_link.cs_previous = NU_NULL; | |
| 1349 suspend_ptr -> qu_message_area = (UNSIGNED_PTR) message; | |
| 1350 suspend_ptr -> qu_message_size = size; | |
| 1351 task = (TC_TCB *) TCT_Current_Thread(); | |
| 1352 suspend_ptr -> qu_suspended_task = task; | |
| 1353 | |
| 1354 /* Determine if priority or FIFO suspension is associated with the | |
| 1355 queue. */ | |
| 1356 if (queue -> qu_fifo_suspend) | |
| 1357 { | |
| 1358 | |
| 1359 /* FIFO suspension is required. Link the suspend block into | |
| 1360 the list of suspended tasks on this queue. */ | |
| 1361 CSC_Place_On_List((CS_NODE **) &(queue -> qu_suspension_list), | |
| 1362 &(suspend_ptr -> qu_suspend_link)); | |
| 1363 } | |
| 1364 else | |
| 1365 { | |
| 1366 | |
| 1367 /* Get the priority of the current thread so the suspend block | |
| 1368 can be placed in the appropriate place. */ | |
| 1369 suspend_ptr -> qu_suspend_link.cs_priority = | |
| 1370 TCC_Task_Priority(task); | |
| 1371 | |
| 1372 CSC_Priority_Place_On_List((CS_NODE **) | |
| 1373 &(queue -> qu_suspension_list), | |
| 1374 &(suspend_ptr -> qu_suspend_link)); | |
| 1375 } | |
| 1376 | |
| 1377 /* Finally, suspend the calling task. Note that the suspension call | |
| 1378 automatically clears the protection on the queue. */ | |
| 1379 TCC_Suspend_Task((NU_TASK *) task, NU_QUEUE_SUSPEND, | |
| 1380 QUC_Cleanup, suspend_ptr, suspend); | |
| 1381 | |
| 1382 /* Pickup the status of the request. */ | |
| 1383 status = suspend_ptr -> qu_return_status; | |
| 1384 *actual_size = suspend_ptr -> qu_actual_size; | |
| 1385 } | |
| 1386 else | |
| 1387 { | |
| 1388 | |
| 1389 /* Return a status of NU_QUEUE_EMPTY because there are no | |
| 1390 messages in the queue. */ | |
| 1391 status = NU_QUEUE_EMPTY; | |
| 1392 | |
| 1393 #ifdef INCLUDE_PROVIEW | |
| 1394 _RTProf_DumpQueue(RT_PROF_RECEIVE_FROM_QUEUE,queue,RT_PROF_FAIL); | |
| 1395 #endif | |
| 1396 | |
| 1397 } | |
| 1398 } | |
| 1399 | |
| 1400 /* Release protection against access to the queue. */ | |
| 1401 TCT_Unprotect(); | |
| 1402 | |
| 1403 /* Return to user mode */ | |
| 1404 NU_USER_MODE(); | |
| 1405 | |
| 1406 /* Return the completion status. */ | |
| 1407 return(status); | |
| 1408 } | |
| 1409 | |
| 1410 | |
| 1411 /*************************************************************************/ | |
| 1412 /* */ | |
| 1413 /* FUNCTION */ | |
| 1414 /* */ | |
| 1415 /* QUC_Cleanup */ | |
| 1416 /* */ | |
| 1417 /* DESCRIPTION */ | |
| 1418 /* */ | |
| 1419 /* This function is responsible for removing a suspension block */ | |
| 1420 /* from a queue. It is not called unless a timeout or a task */ | |
| 1421 /* terminate is in progress. Note that protection is already in */ | |
| 1422 /* effect - the same protection at suspension time. This routine */ | |
| 1423 /* must be called from Supervisor mode in Supervisor/User mode */ | |
| 1424 /* switching kernels. */ | |
| 1425 /* */ | |
| 1426 /* CALLED BY */ | |
| 1427 /* */ | |
| 1428 /* TCC_Timeout Task timeout */ | |
| 1429 /* TCC_Terminate Task terminate */ | |
| 1430 /* */ | |
| 1431 /* CALLS */ | |
| 1432 /* */ | |
| 1433 /* CSC_Remove_From_List Remove suspend block from */ | |
| 1434 /* the suspension list */ | |
| 1435 /* */ | |
| 1436 /* INPUTS */ | |
| 1437 /* */ | |
| 1438 /* information Pointer to suspend block */ | |
| 1439 /* */ | |
| 1440 /* OUTPUTS */ | |
| 1441 /* */ | |
| 1442 /* None */ | |
| 1443 /* */ | |
| 1444 /* HISTORY */ | |
| 1445 /* */ | |
| 1446 /* DATE REMARKS */ | |
| 1447 /* */ | |
| 1448 /* 03-01-1993 Created initial version 1.0 */ | |
| 1449 /* 04-19-1993 Verified version 1.0 */ | |
| 1450 /* */ | |
| 1451 /*************************************************************************/ | |
| 1452 VOID QUC_Cleanup(VOID *information) | |
| 1453 { | |
| 1454 | |
| 1455 QU_SUSPEND *suspend_ptr; /* Suspension block pointer */ | |
| 1456 NU_SUPERV_USER_VARIABLES | |
| 1457 | |
| 1458 /* Switch to supervisor mode */ | |
| 1459 NU_SUPERVISOR_MODE(); | |
| 1460 | |
| 1461 /* Use the information pointer as a suspend pointer. */ | |
| 1462 suspend_ptr = (QU_SUSPEND *) information; | |
| 1463 | |
| 1464 /* By default, indicate that the service timed-out. It really does not | |
| 1465 matter if this function is called from a terminate request since | |
| 1466 the task does not resume. */ | |
| 1467 suspend_ptr -> qu_return_status = NU_TIMEOUT; | |
| 1468 | |
| 1469 /* Decrement the number of tasks waiting counter. */ | |
| 1470 (suspend_ptr -> qu_queue) -> qu_tasks_waiting--; | |
| 1471 | |
| 1472 /* Unlink the suspend block from the suspension list. */ | |
| 1473 if ((suspend_ptr -> qu_queue) -> qu_urgent_list) | |
| 1474 { | |
| 1475 /* Unlink the suspend block from the suspension list. */ | |
| 1476 CSC_Remove_From_List((CS_NODE **) | |
| 1477 &((suspend_ptr -> qu_queue) -> qu_urgent_list), | |
| 1478 &(suspend_ptr -> qu_suspend_link)); | |
| 1479 } | |
| 1480 else | |
| 1481 { | |
| 1482 /* Unlink the suspend block from the suspension list. */ | |
| 1483 CSC_Remove_From_List((CS_NODE **) | |
| 1484 &((suspend_ptr -> qu_queue) -> qu_suspension_list), | |
| 1485 &(suspend_ptr -> qu_suspend_link)); | |
| 1486 } | |
| 1487 | |
| 1488 /* Return to user mode */ | |
| 1489 NU_USER_MODE(); | |
| 1490 } | |
| 1491 | |
| 1492 | |
| 1493 | |
| 1494 | |
| 1495 | |
| 1496 |
