FreeCalypso > hg > fc-tourmaline
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 |