comparison src/nucleus/quc.c @ 0:4e78acac3d88

src/{condat,cs,gpf,nucleus}: import from Selenite
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 16 Oct 2020 06:23:26 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4e78acac3d88
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