comparison src/nucleus/pis.c @ 0:92470e5d0b9e

src: partial import from FC Selenite
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 15 May 2020 01:28:16 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:92470e5d0b9e
1 /*************************************************************************/
2 /* */
3 /* Copyright Mentor Graphics Corporation 2002 */
4 /* All Rights Reserved. */
5 /* */
6 /* THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS */
7 /* THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS */
8 /* SUBJECT TO LICENSE TERMS. */
9 /* */
10 /*************************************************************************/
11
12 /*************************************************************************/
13 /* */
14 /* FILE NAME VERSION */
15 /* */
16 /* pis.c Nucleus PLUS 1.14 */
17 /* */
18 /* COMPONENT */
19 /* */
20 /* PI - Pipe Management */
21 /* */
22 /* DESCRIPTION */
23 /* */
24 /* This file contains the supplemental routines for the pipe */
25 /* management component. */
26 /* */
27 /* DATA STRUCTURES */
28 /* */
29 /* None */
30 /* */
31 /* FUNCTIONS */
32 /* */
33 /* PIS_Reset_Pipe Reset a pipe */
34 /* PIS_Send_To_Front_Of_Pipe Send message to pipe's front */
35 /* PIS_Broadcast_To_Pipe Broadcast a message to pipe */
36 /* */
37 /* DEPENDENCIES */
38 /* */
39 /* cs_extr.h Common Service functions */
40 /* tc_extr.h Thread Control functions */
41 /* pi_extr.h Pipe functions */
42 /* hi_extr.h History functions */
43 /* */
44 /* HISTORY */
45 /* */
46 /* DATE REMARKS */
47 /* */
48 /* 03-01-1994 Created initial version 1.1 from */
49 /* routines originally in core */
50 /* */
51 /* 03-18-1994 Verified version 1.1 */
52 /* 04-17-1996 updated to version 1.2 */
53 /* 02-04-1998 Corrected SPR434 resulting in */
54 /* version 1.2a. */
55 /* 03-24-1998 Released version 1.3 */
56 /* 03-26-1999 Released 1.11m (new release */
57 /* numbering scheme) */
58 /* 04-17-2002 Released version 1.13m */
59 /* 11-07-2002 Released version 1.14 */
60 /*************************************************************************/
61 #define NU_SOURCE_FILE
62
63
64 #include "cs_extr.h" /* Common service functions */
65 #include "tc_extr.h" /* Thread control functions */
66 #include "pi_extr.h" /* Pipe functions */
67 #include "hi_extr.h" /* History functions */
68 #include "profiler.h" /* ProView interface */
69
70
71 /* Define external inner-component global data references. */
72
73 extern CS_NODE *PID_Created_Pipes_List;
74 extern UNSIGNED PID_Total_Pipes;
75 extern TC_PROTECT PID_List_Protect;
76
77
78 /* Define internal component function prototypes. */
79
80 VOID PIC_Cleanup(VOID *information);
81
82
83 /*************************************************************************/
84 /* */
85 /* FUNCTION */
86 /* */
87 /* PIS_Reset_Pipe */
88 /* */
89 /* DESCRIPTION */
90 /* */
91 /* This function resets the specified pipe back to the original */
92 /* state. Any messages in the pipe are discarded. Also, any */
93 /* tasks currently suspended on the pipe are resumed with the */
94 /* reset status. */
95 /* */
96 /* CALLED BY */
97 /* */
98 /* Application */
99 /* PISE_Reset_Pipe Error checking shell */
100 /* */
101 /* CALLS */
102 /* */
103 /* [HIC_Make_History_Entry] Make entry in history log */
104 /* TCC_Resume_Task Resume a suspended task */
105 /* [TCT_Check_Stack] Stack checking function */
106 /* TCT_Control_To_System Transfer control to system */
107 /* TCT_System_Protect Protect against system access*/
108 /* TCT_Unprotect Release protection */
109 /* */
110 /* INPUTS */
111 /* */
112 /* pipe_ptr Pipe control block pointer */
113 /* */
114 /* OUTPUTS */
115 /* */
116 /* NU_SUCCESS */
117 /* */
118 /* HISTORY */
119 /* */
120 /* NAME DATE REMARKS */
121 /* */
122 /* 03-01-1993 Created initial version 1.0 */
123 /* 04-19-1993 Verified version 1.0 */
124 /* 03-01-1994 Changed function interfaces to */
125 /* match those in prototype, */
126 /* added register options, changed */
127 /* protection logic to reduce */
128 /* overhead, fixed read and write */
129 /* pointers to both point at the */
130 /* start, resulting in version 1.1 */
131 /* */
132 /* 03-18-1994 Verified version 1.1 */
133 /* 02-04-1998 Corrected SPR434. */
134 /* */
135 /*************************************************************************/
136 STATUS PIS_Reset_Pipe(NU_PIPE *pipe_ptr)
137 {
138
139 R1 PI_PCB *pipe; /* Pipe control block ptr */
140 PI_SUSPEND *suspend_ptr; /* Suspend block pointer */
141 PI_SUSPEND *next_ptr; /* Next suspend block pointer*/
142 STATUS preempt; /* Status for resume call */
143 NU_SUPERV_USER_VARIABLES
144
145 /* Switch to supervisor mode */
146 NU_SUPERVISOR_MODE();
147
148 /* Move input pipe pointer into internal pointer. */
149 pipe = (PI_PCB *) pipe_ptr;
150
151
152 #ifdef NU_ENABLE_STACK_CHECK
153
154 /* Call stack checking function to check for an overflow condition. */
155 TCT_Check_Stack();
156
157 #endif
158
159 #ifdef NU_ENABLE_HISTORY
160
161 /* Make an entry that corresponds to this function in the system history
162 log. */
163 HIC_Make_History_Entry(NU_RESET_PIPE_ID, (UNSIGNED) pipe,
164 (UNSIGNED) 0, (UNSIGNED) 0);
165
166 #endif
167
168 /* Protect against access to the pipe. */
169 TCT_System_Protect();
170
171 /* Pickup the suspended task suspension list. */
172 suspend_ptr = pipe -> pi_suspension_list;
173
174 /* Walk the chain task(s) currently suspended on the pipe. */
175 preempt = 0;
176 while (suspend_ptr)
177 {
178
179 /* Resume the suspended task. Insure that the status returned is
180 NU_PIPE_RESET. */
181 suspend_ptr -> pi_return_status = NU_PIPE_RESET;
182
183 /* Point to the next suspend structure in the link. */
184 next_ptr = (PI_SUSPEND *) (suspend_ptr -> pi_suspend_link.cs_next);
185
186 /* Resume the specified task. */
187 preempt = preempt |
188 TCC_Resume_Task((NU_TASK *) suspend_ptr -> pi_suspended_task,
189 NU_PIPE_SUSPEND);
190
191 /* Determine if the next is the same as the head pointer. */
192 if (next_ptr == pipe -> pi_suspension_list)
193
194 /* Clear the suspension pointer to signal the end of the list
195 traversal. */
196 suspend_ptr = NU_NULL;
197 else
198
199 /* Position the suspend pointer to the next block. */
200 suspend_ptr = next_ptr;
201 }
202
203 /* Pickup the urgent message suspension list. */
204 suspend_ptr = pipe -> pi_urgent_list;
205
206 /* Walk the chain task(s) currently suspended on the pipe. */
207 while (suspend_ptr)
208 {
209
210 /* Resume the suspended task. Insure that the status returned is
211 NU_PIPE_RESET. */
212 suspend_ptr -> pi_return_status = NU_PIPE_RESET;
213
214 /* Point to the next suspend structure in the link. */
215 next_ptr = (PI_SUSPEND *) (suspend_ptr -> pi_suspend_link.cs_next);
216
217 /* Resume the specified task. */
218 preempt = preempt |
219 TCC_Resume_Task((NU_TASK *) suspend_ptr -> pi_suspended_task,
220 NU_PIPE_SUSPEND);
221
222 /* Determine if the next is the same as the head pointer. */
223 if (next_ptr == pipe -> pi_urgent_list)
224
225 /* Clear the suspension pointer to signal the end of the list
226 traversal. */
227 suspend_ptr = NU_NULL;
228 else
229
230 /* Position the suspend pointer to the next active block. */
231 suspend_ptr = next_ptr;
232 }
233
234 /* Initialize various elements of the pipe. */
235 pipe -> pi_available = pipe -> pi_end - pipe -> pi_start;
236 pipe -> pi_messages = 0;
237 pipe -> pi_read = pipe -> pi_start;
238 pipe -> pi_write = pipe -> pi_start;
239 pipe -> pi_tasks_waiting = 0;
240 pipe -> pi_suspension_list = NU_NULL;
241 pipe -> pi_urgent_list = NU_NULL;
242
243 #ifdef INCLUDE_PROVIEW
244 _RTProf_DumpPipe(RT_PROF_RESET_PIPE,pipe,RT_PROF_OK);
245 #endif /* INCLUDE_PROVIEW */
246
247 /* Determine if preemption needs to occur. */
248 if (preempt)
249
250 /* Transfer control to system to facilitate preemption. */
251 TCT_Control_To_System();
252
253 /* Release protection against access to the pipe. */
254 TCT_Unprotect();
255
256 /* Return to user mode */
257 NU_USER_MODE();
258
259 /* Return a successful completion. */
260 return(NU_SUCCESS);
261 }
262
263
264 /*************************************************************************/
265 /* */
266 /* FUNCTION */
267 /* */
268 /* PIS_Send_To_Front_Of_Pipe */
269 /* */
270 /* DESCRIPTION */
271 /* */
272 /* This function sends a message to the front of the specified */
273 /* message pipe. The message length is determined by the caller. */
274 /* If there are any tasks suspended on the pipe for a message, the */
275 /* message is copied into the message area of the first waiting */
276 /* task and that task is resumed. If there is enough room in the */
277 /* pipe, the message is copied in front of all other messages. */
278 /* If there is not enough room in the pipe, suspension of the */
279 /* caller is possible. */
280 /* */
281 /* CALLED BY */
282 /* */
283 /* Application */
284 /* PISE_Send_To_Front_Of_Pipe Error checking shell */
285 /* */
286 /* CALLS */
287 /* */
288 /* CSC_Place_On_List Place on suspend list */
289 /* CSC_Remove_From_List Remove from suspend list */
290 /* [HIC_Make_History_Entry] Make entry in history log */
291 /* TCC_Resume_Task Resume a suspended task */
292 /* TCC_Suspend_Task Suspend calling task */
293 /* [TCT_Check_Stack] Stack checking function */
294 /* TCT_Control_To_System Transfer control to system */
295 /* TCT_Current_Thread Pickup current thread pointer*/
296 /* TCT_System_Protect Protect pipe */
297 /* TCT_Unprotect Release protection */
298 /* */
299 /* INPUTS */
300 /* */
301 /* pipe_ptr Pipe control block pointer */
302 /* message Pointer to message to send */
303 /* size Size of message to send */
304 /* suspend Suspension option if full */
305 /* */
306 /* OUTPUTS */
307 /* */
308 /* NU_SUCCESS If service is successful */
309 /* NU_PIPE_FULL If pipe is currently full */
310 /* NU_TIMEOUT If timeout on service expires*/
311 /* NU_PIPE_DELETED If pipe was deleted during */
312 /* suspension */
313 /* NU_PIPE_RESET If pipe was reset during */
314 /* suspension */
315 /* */
316 /* HISTORY */
317 /* */
318 /* DATE REMARKS */
319 /* */
320 /* 03-01-1993 Created initial version 1.0 */
321 /* 04-19-1993 Verified version 1.0 */
322 /* 03-01-1994 Changed function interfaces to */
323 /* match those in prototype, */
324 /* added register options, changed */
325 /* protection logic to reduce */
326 /* overhead, optimized copy loop, */
327 /* resulting in version 1.1 */
328 /* */
329 /* 03-18-1994 Verified version 1.1 */
330 /* */
331 /*************************************************************************/
332 STATUS PIS_Send_To_Front_Of_Pipe(NU_PIPE *pipe_ptr, VOID *message,
333 UNSIGNED size, UNSIGNED suspend)
334 {
335
336 R1 PI_PCB *pipe; /* Pipe control block ptr */
337 PI_SUSPEND suspend_block; /* Allocate suspension block */
338 PI_SUSPEND *suspend_ptr; /* Pointer to suspend block */
339 R2 BYTE_PTR source; /* Pointer to source */
340 R3 BYTE_PTR destination; /* Pointer to destination */
341 UNSIGNED copy_size; /* Partial copy size */
342 R4 INT i; /* Working counter */
343 UNSIGNED pad = 0; /* Number of pad bytes */
344 TC_TCB *task; /* Task pointer */
345 STATUS preempt; /* Preempt flag */
346 STATUS status; /* Completion status */
347 NU_SUPERV_USER_VARIABLES
348
349 /* Switch to supervisor mode */
350 NU_SUPERVISOR_MODE();
351
352 /* Move input pipe pointer into internal pointer. */
353 pipe = (PI_PCB *) pipe_ptr;
354
355
356 #ifdef NU_ENABLE_STACK_CHECK
357
358 /* Call stack checking function to check for an overflow condition. */
359 TCT_Check_Stack();
360
361 #endif
362
363 #ifdef NU_ENABLE_HISTORY
364
365 /* Make an entry that corresponds to this function in the system history
366 log. */
367 HIC_Make_History_Entry(NU_SEND_TO_FRONT_OF_PIPE_ID, (UNSIGNED) pipe,
368 (UNSIGNED) message, (UNSIGNED) size);
369
370 #endif
371
372 /* Initialize the status as successful. */
373 status = NU_SUCCESS;
374
375 /* Protect against simultaneous access to the pipe. */
376 TCT_System_Protect();
377
378 /* Determine if an extra word of overhead needs to be added to the
379 calculation. */
380 if (pipe -> pi_fixed_size)
381
382 /* No overhead. */
383 i = 0;
384 else
385 {
386
387 /* Variable messages have one additional word of overhead. */
388 i = sizeof(UNSIGNED);
389
390 /* Calculate the number of pad bytes necessary to keep the pipe
391 write pointer on an UNSIGNED data element alignment. */
392 pad = (((size + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) *
393 sizeof(UNSIGNED)) - size;
394
395 /* Insure that padding is included in the overhead. */
396 i = i + ((INT) pad);
397
398 /* Make special check to see if a suspension needs to be
399 forced for a variable length message. */
400 if ((pipe -> pi_suspension_list) && (pipe -> pi_messages))
401 {
402
403 /* Pickup task control block pointer. */
404 task = (TC_TCB *) TCT_Current_Thread();
405
406 /* Now we know that there are other task(s) are suspended trying
407 to send a variable length message. Determine whether or not
408 a suspension should be forced. */
409 if ((pipe -> pi_fifo_suspend) ||
410 (suspend == NU_NO_SUSPEND) ||
411 ((pipe -> pi_suspension_list) -> pi_suspend_link.cs_priority <=
412 TCC_Task_Priority(task)))
413
414 /* Bump the computed size to avoid placing the new variable
415 length message ahead of the suspended tasks. */
416 i = (INT) pipe -> pi_available;
417 }
418 }
419
420 /* Determine if there is enough room in the pipe for the message. */
421 if (pipe -> pi_available < (size + i))
422 {
423
424 /* pipe does not have room for the message. Determine if
425 suspension is required. */
426 if (suspend)
427 {
428
429 /* Suspension is requested. */
430
431 /* Increment the number of tasks waiting. */
432 pipe -> pi_tasks_waiting++;
433
434 #ifdef INCLUDE_PROVIEW
435 _RTProf_DumpPipe(RT_PROF_SEND_TO_FRONT_OF_PIPE,pipe,RT_PROF_WAIT);
436 #endif /* INCLUDE_PROVIEW */
437
438 /* Setup the suspend block and suspend the calling task. */
439 suspend_ptr = &suspend_block;
440 suspend_ptr -> pi_pipe = pipe;
441 suspend_ptr -> pi_suspend_link.cs_next = NU_NULL;
442 suspend_ptr -> pi_suspend_link.cs_previous = NU_NULL;
443 suspend_ptr -> pi_message_area = (BYTE_PTR) message;
444 suspend_ptr -> pi_message_size = size;
445 task = (TC_TCB *) TCT_Current_Thread();
446 suspend_ptr -> pi_suspended_task = task;
447
448 /* Place the task on the urgent message suspension list. */
449 CSC_Place_On_List((CS_NODE **) &(pipe -> pi_urgent_list),
450 &(suspend_ptr -> pi_suspend_link));
451
452 /* Move the head pointer of the list to make this suspension the
453 first in the list. */
454 pipe -> pi_urgent_list = (PI_SUSPEND *)
455 (pipe -> pi_urgent_list) -> pi_suspend_link.cs_previous;
456
457 /* Finally, suspend the calling task. Note that the suspension call
458 automatically clears the protection on the pipe. */
459 TCC_Suspend_Task((NU_TASK *) task, NU_PIPE_SUSPEND,
460 PIC_Cleanup, suspend_ptr, suspend);
461
462 /* Pickup the return status. */
463 status = suspend_ptr -> pi_return_status;
464 }
465 else
466 {
467
468 /* Return a status of NU_PIPE_FULL because there is no
469 room in the pipe for the message. */
470 status = NU_PIPE_FULL;
471
472 #ifdef INCLUDE_PROVIEW
473 _RTProf_DumpPipe(RT_PROF_SEND_TO_FRONT_OF_PIPE,pipe,RT_PROF_FAIL);
474 #endif /* INCLUDE_PROVIEW */
475
476 }
477 }
478 else
479 {
480
481 /* Determine if a task is waiting on an empty pipe. */
482 if ((pipe -> pi_suspension_list) && (pipe -> pi_messages == 0))
483 {
484
485 /* Task is waiting on pipe for a message. */
486
487 /* Decrement the number of tasks waiting on pipe. */
488 pipe -> pi_tasks_waiting--;
489
490 #ifdef INCLUDE_PROVIEW
491 _RTProf_DumpPipe(RT_PROF_SEND_TO_FRONT_OF_PIPE,pipe,RT_PROF_OK);
492 #endif /* INCLUDE_PROVIEW */
493
494 /* Remove the first suspended block from the list. */
495 suspend_ptr = pipe -> pi_suspension_list;
496 CSC_Remove_From_List((CS_NODE **) &(pipe -> pi_suspension_list),
497 &(suspend_ptr -> pi_suspend_link));
498
499 /* Setup the source and destination pointers. */
500 source = (BYTE_PTR) message;
501 destination = suspend_ptr -> pi_message_area;
502
503 /* Initialize the return status. */
504 suspend_ptr -> pi_return_status = NU_SUCCESS;
505
506 /* Loop to actually copy the message. */
507 i = (INT) size;
508 do
509 {
510 *(destination++) = *(source);
511 if ((--i) == 0)
512 break;
513 source++;
514 } while (1);
515
516 /* Return the size of the message copied. */
517 suspend_ptr -> pi_actual_size = size;
518
519 /* Wakeup the waiting task and check for preemption. */
520 preempt =
521 TCC_Resume_Task((NU_TASK *) suspend_ptr -> pi_suspended_task,
522 NU_PIPE_SUSPEND);
523
524 /* Determine if preemption needs to take place. */
525 if (preempt)
526
527 /* Transfer control to the system if the resumed task function
528 detects a preemption condition. */
529 TCT_Control_To_System();
530 }
531 else
532 {
533
534 /* There is enough room in the pipe and no task is waiting. */
535
536 /* Setup the source pointer. */
537 source = (BYTE_PTR) message;
538 destination = pipe -> pi_read;
539
540 /* Process according to the type of message supported. */
541 if (pipe -> pi_fixed_size)
542 {
543
544 /* Fixed-size message pipe. */
545
546 /* Determine if the read pointer is at the top of the pipe
547 area. */
548 if (destination == pipe -> pi_start)
549
550 /* Prepare to place the message in the lower part of the
551 pipe area. */
552 destination = pipe -> pi_end - size;
553 else
554
555 /* Backup the length of the message from the current
556 read pointer. */
557 destination = destination - size;
558
559 /* Adjust the actual read pointer before the copy is done. */
560 pipe -> pi_read = destination;
561
562 /* Copy the message into the pipe area. */
563 i = (INT) size;
564 do
565 {
566 *(destination++) = *(source);
567 if ((--i) == 0)
568 break;
569 source++;
570 } while (1);
571 }
572 else
573 {
574
575 /* Variable-length message pipe. */
576
577 /* Calculate the number of bytes remaining from the write
578 pointer to the bottom of the pipe. */
579 copy_size = destination - pipe -> pi_start;
580
581 /* Determine if part of the message needs to be placed at the
582 bottom of the pipe area. */
583 if (copy_size < (size + i))
584
585 /* Compute the starting location for the message. */
586 destination = pipe -> pi_end - ((size + i) - copy_size);
587 else
588
589 /* Compute the starting location for the message. */
590 destination = destination - (size + i);
591
592 /* Adjust the actual pipe read pointer also. */
593 pipe -> pi_read = destination;
594
595 /* Place message size in first location. */
596 *((UNSIGNED *) destination) = size;
597 destination = destination + sizeof(UNSIGNED);
598
599 /* Check for a wrap-around condition on the pipe. */
600 if (destination >= pipe -> pi_end)
601
602 /* Wrap the write pointer back to the top of the pipe
603 area. */
604 destination = pipe -> pi_start;
605
606 /* Decrement the number of bytes remaining for this
607 extra word of overhead. */
608 pipe -> pi_available = pipe -> pi_available -
609 sizeof(UNSIGNED);
610
611 /* Calculate the number of bytes remaining from the write
612 pointer to the bottom of the pipe. */
613 copy_size = pipe -> pi_end - destination;
614
615 /* Determine if the message needs to be wrapped around the
616 edge of the pipe area. */
617 if (copy_size >= (size + pad))
618 {
619
620 /* Copy the whole message at once. */
621 i = (INT) size;
622 do
623 {
624 *(destination++) = *(source);
625 if ((--i) == 0)
626 break;
627 source++;
628 } while (1);
629 }
630 else
631 {
632
633 /* Copy the first half of the message. */
634 i = (INT) copy_size;
635 do
636 {
637 *(destination) = *(source++);
638 if ((--i) == 0)
639 break;
640 destination++;
641 } while (1);
642
643 /* Copy the second half of the message. */
644 destination = pipe -> pi_start;
645
646 /* Determine if there is anything left to copy. */
647 if (size > copy_size)
648 {
649 /* Yes, there is something to copy. */
650 i = (INT) (size - copy_size);
651 do
652 {
653 *(destination++) = *(source);
654 if ((--i) == 0)
655 break;
656 source++;
657 } while (1);
658 }
659 }
660 /* Decrement the number of available bytes. */
661 pipe -> pi_available = pipe -> pi_available - pad;
662 }
663
664 /* Decrement the number of available bytes. */
665 pipe -> pi_available = pipe -> pi_available - size;
666
667 /* Increment the number of messages in the pipe. */
668 pipe -> pi_messages++;
669
670 #ifdef INCLUDE_PROVIEW
671 _RTProf_DumpPipe(RT_PROF_SEND_TO_FRONT_OF_PIPE,pipe,RT_PROF_OK);
672 #endif /* INCLUDE_PROVIEW */
673
674 }
675 }
676
677 /* Release protection against access to the pipe. */
678 TCT_Unprotect();
679
680 /* Return to user mode */
681 NU_USER_MODE();
682
683 /* Return the completion status. */
684 return(status);
685 }
686
687
688 /*************************************************************************/
689 /* */
690 /* FUNCTION */
691 /* */
692 /* PIS_Broadcast_To_Pipe */
693 /* */
694 /* DESCRIPTION */
695 /* */
696 /* This function sends a message to all tasks waiting for a message */
697 /* from the specified pipe. If there are no tasks waiting for a */
698 /* message the service performs like a standard send request. */
699 /* */
700 /* CALLED BY */
701 /* */
702 /* Application */
703 /* PISE_Broadcast_To_Pipe Error checking shell */
704 /* */
705 /* CALLS */
706 /* */
707 /* CSC_Place_On_List Place on suspend list */
708 /* CSC_Priority_Place_On_List Place on priority list */
709 /* CSC_Remove_From_List Remove from suspend list */
710 /* [HIC_Make_History_Entry] Make entry in history log */
711 /* TCC_Resume_Task Resume a suspended task */
712 /* TCC_Suspend_Task Suspend calling task */
713 /* TCC_Task_Priority Pickup task's priority */
714 /* [TCT_Check_Stack] Stack checking function */
715 /* TCT_Control_To_System Transfer control to system */
716 /* TCT_Current_Thread Pickup current thread pointer*/
717 /* TCT_System_Protect Protect pipe */
718 /* TCT_Unprotect Release protection */
719 /* */
720 /* INPUTS */
721 /* */
722 /* pipe_ptr Pipe control block pointer */
723 /* message Pointer to message to send */
724 /* size Size of message to send */
725 /* suspend Suspension option if full */
726 /* */
727 /* OUTPUTS */
728 /* */
729 /* NU_SUCCESS If service is successful */
730 /* NU_PIPE_FULL If pipe is currently full */
731 /* NU_TIMEOUT If timeout on service expires*/
732 /* NU_PIPE_DELETED If pipe was deleted during */
733 /* suspension */
734 /* NU_PIPE_RESET If pipe was reset during */
735 /* suspension */
736 /* */
737 /* HISTORY */
738 /* */
739 /* DATE REMARKS */
740 /* */
741 /* 03-01-1993 Created initial version 1.0 */
742 /* 04-19-1993 Verified version 1.0 */
743 /* 03-01-1994 Changed function interfaces to */
744 /* match those in prototype, */
745 /* added register options, changed */
746 /* protection logic to reduce */
747 /* overhead, optimized copy loop, */
748 /* resulting in version 1.1 */
749 /* */
750 /* 03-18-1994 Verified version 1.1 */
751 /* */
752 /*************************************************************************/
753 STATUS PIS_Broadcast_To_Pipe(NU_PIPE *pipe_ptr, VOID *message,
754 UNSIGNED size, UNSIGNED suspend)
755 {
756
757 R1 PI_PCB *pipe; /* Pipe control block ptr */
758 PI_SUSPEND suspend_block; /* Allocate suspension block */
759 PI_SUSPEND *suspend_ptr; /* Pointer to suspend block */
760 R2 BYTE_PTR source; /* Pointer to source */
761 R3 BYTE_PTR destination; /* Pointer to destination */
762 UNSIGNED copy_size; /* Partial copy size */
763 UNSIGNED pad = 0; /* Number of pad bytes */
764 R4 INT i; /* Working counter */
765 TC_TCB *task; /* Task pointer */
766 STATUS preempt; /* Preempt flag */
767 STATUS status; /* Completion status */
768 NU_SUPERV_USER_VARIABLES
769
770 /* Switch to supervisor mode */
771 NU_SUPERVISOR_MODE();
772
773 /* Move input pipe pointer into internal pointer. */
774 pipe = (PI_PCB *) pipe_ptr;
775
776
777 #ifdef NU_ENABLE_STACK_CHECK
778
779 /* Call stack checking function to check for an overflow condition. */
780 TCT_Check_Stack();
781
782 #endif
783
784 #ifdef NU_ENABLE_HISTORY
785
786 /* Make an entry that corresponds to this function in the system history
787 log. */
788 HIC_Make_History_Entry(NU_BROADCAST_TO_PIPE_ID, (UNSIGNED) pipe,
789 (UNSIGNED) message, (UNSIGNED) size);
790
791 #endif
792
793 /* Initialize the status as successful. */
794 status = NU_SUCCESS;
795
796 /* Protect against simultaneous access to the pipe. */
797 TCT_System_Protect();
798
799 /* Determine if an extra word of overhead needs to be added to the
800 calculation. */
801 if (pipe -> pi_fixed_size)
802
803 /* No overhead. */
804 i = 0;
805 else
806 {
807
808 /* Variable messages have one additional word of overhead. */
809 i = sizeof(UNSIGNED);
810
811 /* Calculate the number of pad bytes necessary to keep the pipe
812 write pointer on an UNSIGNED data element alignment. */
813 pad = (((size + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) *
814 sizeof(UNSIGNED)) - size;
815
816 /* Insure that padding is included in the overhead. */
817 i = i + ((INT) pad);
818
819 /* Make special check to see if a suspension needs to be
820 forced for a variable length message. */
821 if ((pipe -> pi_suspension_list) && (pipe -> pi_messages))
822 {
823
824 /* Pickup task control block pointer. */
825 task = (TC_TCB *) TCT_Current_Thread();
826
827 /* Now we know that there are other task(s) are suspended trying
828 to send a variable length message. Determine whether or not
829 a suspension should be forced. */
830 if ((pipe -> pi_fifo_suspend) ||
831 (suspend == NU_NO_SUSPEND) ||
832 ((pipe -> pi_suspension_list) -> pi_suspend_link.cs_priority <=
833 TCC_Task_Priority(task)))
834
835 /* Bump the computed size to avoid placing the new variable
836 length message ahead of the suspended tasks. */
837 i = (INT) pipe -> pi_available;
838 }
839 }
840
841 /* Determine if there is enough room in the pipe for the message. */
842 if (pipe -> pi_available < (size + i))
843 {
844
845 /* pipe does not have room for the message. Determine if
846 suspension is required. */
847 if (suspend)
848 {
849
850 /* Suspension is requested. */
851
852 /* Increment the number of tasks waiting. */
853 pipe -> pi_tasks_waiting++;
854
855 #ifdef INCLUDE_PROVIEW
856 _RTProf_DumpPipe(RT_PROF_BROADCAST_TO_PIPE,pipe,RT_PROF_WAIT);
857 #endif /* INCLUDE_PROVIEW */
858
859 /* Setup the suspend block and suspend the calling task. */
860 suspend_ptr = &suspend_block;
861 suspend_ptr -> pi_pipe = pipe;
862 suspend_ptr -> pi_suspend_link.cs_next = NU_NULL;
863 suspend_ptr -> pi_suspend_link.cs_previous = NU_NULL;
864 suspend_ptr -> pi_message_area = (BYTE_PTR) message;
865 suspend_ptr -> pi_message_size = size;
866 task = (TC_TCB *) TCT_Current_Thread();
867 suspend_ptr -> pi_suspended_task = task;
868
869 /* Determine if priority or FIFO suspension is associated with the
870 pipe. */
871 if (pipe -> pi_fifo_suspend)
872 {
873
874 /* FIFO suspension is required. Link the suspend block into
875 the list of suspended tasks on this pipe. */
876 CSC_Place_On_List((CS_NODE **) &(pipe -> pi_suspension_list),
877 &(suspend_ptr -> pi_suspend_link));
878 }
879 else
880 {
881
882 /* Get the priority of the current thread so the suspend block
883 can be placed in the appropriate place. */
884 suspend_ptr -> pi_suspend_link.cs_priority =
885 TCC_Task_Priority(task);
886
887 CSC_Priority_Place_On_List((CS_NODE **)
888 &(pipe -> pi_suspension_list),
889 &(suspend_ptr -> pi_suspend_link));
890 }
891
892 /* Finally, suspend the calling task. Note that the suspension call
893 automatically clears the protection on the pipe. */
894 TCC_Suspend_Task((NU_TASK *) task, NU_PIPE_SUSPEND,
895 PIC_Cleanup, suspend_ptr, suspend);
896
897 /* Pickup the return status. */
898 status = suspend_ptr -> pi_return_status;
899 }
900 else
901 {
902
903 /* Return a status of NU_PIPE_FULL because there is no
904 room in the pipe for the message. */
905 status = NU_PIPE_FULL;
906
907
908 #ifdef INCLUDE_PROVIEW
909 _RTProf_DumpPipe(RT_PROF_BROADCAST_TO_PIPE,pipe,RT_PROF_FAIL);
910 #endif /* INCLUDE_PROVIEW */
911
912 }
913 }
914 else
915 {
916
917 #ifdef INCLUDE_PROVIEW
918 _RTProf_DumpPipe(RT_PROF_BROADCAST_TO_PIPE,pipe,RT_PROF_OK);
919 #endif /* INCLUDE_PROVIEW */
920
921 /* Determine if a task is waiting on an empty pipe. */
922 if ((pipe -> pi_suspension_list) && (pipe -> pi_messages == 0))
923 {
924
925 /* Yes, one or more tasks are waiting for a message from this
926 pipe. */
927 preempt = 0;
928 do
929 {
930
931 /* Decrement the number of tasks waiting on pipe. */
932 pipe -> pi_tasks_waiting--;
933
934 /* Remove the first suspended block from the list. */
935 suspend_ptr = pipe -> pi_suspension_list;
936 CSC_Remove_From_List((CS_NODE **)
937 &(pipe -> pi_suspension_list),
938 &(suspend_ptr -> pi_suspend_link));
939
940 /* Setup the source and destination pointers. */
941 source = (BYTE_PTR) message;
942 destination = suspend_ptr -> pi_message_area;
943
944 /* Initialize the return status. */
945 suspend_ptr -> pi_return_status = NU_SUCCESS;
946
947 /* Loop to actually copy the message. */
948 i = (INT) size;
949 do
950 {
951 *(destination++) = *(source);
952 if ((--i) == 0)
953 break;
954 source++;
955 } while (1);
956
957 /* Return the size of the message copied. */
958 suspend_ptr -> pi_actual_size = size;
959
960 /* Wakeup the waiting task and check for preemption. */
961 preempt = preempt |
962 TCC_Resume_Task((NU_TASK *) suspend_ptr -> pi_suspended_task,
963 NU_PIPE_SUSPEND);
964
965 /* Move the suspend pointer to the next node, which is now
966 at the head of the list. */
967 suspend_ptr = pipe -> pi_suspension_list;
968 } while (suspend_ptr);
969
970 /* Determine if preemption needs to take place. */
971 if (preempt)
972
973 /* Transfer control to the system if the resumed task function
974 detects a preemption condition. */
975 TCT_Control_To_System();
976 }
977 else
978 {
979
980 /* There is enough room in the pipe and no task is waiting. */
981
982 /* Setup the source pointer. */
983 source = (BYTE_PTR) message;
984 destination = pipe -> pi_write;
985
986 /* Process according to the type of message supported. */
987 if (pipe -> pi_fixed_size)
988 {
989
990 /* Fixed-size messages are supported by this pipe. */
991
992 /* Loop to copy the message into the pipe area. */
993 i = (INT) size;
994 do
995 {
996 *(destination++) = *(source);
997 if ((--i) == 0)
998 break;
999 source++;
1000 } while (1);
1001 }
1002 else
1003 {
1004
1005 /* Variable-size messages are supported. Processing must
1006 check for pipe wrap-around conditions. */
1007
1008 /* Place message size in first location. */
1009 *((UNSIGNED *) destination) = size;
1010 destination = destination + sizeof(UNSIGNED);
1011
1012 /* Check for a wrap-around condition on the pipe. */
1013 if (destination >= pipe -> pi_end)
1014
1015 /* Wrap the write pointer back to the top of the pipe
1016 area. */
1017 destination = pipe -> pi_start;
1018
1019 /* Decrement the number of bytes remaining for this
1020 extra word of overhead. */
1021 pipe -> pi_available = pipe -> pi_available -
1022 sizeof(UNSIGNED);
1023
1024 /* Calculate the number of bytes remaining from the write
1025 pointer to the bottom of the pipe. */
1026 copy_size = pipe -> pi_end - destination;
1027
1028 /* Determine if the message needs to be wrapped around the
1029 edge of the pipe area. */
1030 if (copy_size >= size)
1031 {
1032
1033 /* Copy the whole message at once. */
1034 i = (INT) size;
1035 do
1036 {
1037 *(destination++) = *(source);
1038 if ((--i) == 0)
1039 break;
1040 source++;
1041 } while (1);
1042 }
1043 else
1044 {
1045
1046 /* Copy the first half of the message. */
1047 i = (INT) copy_size;
1048 do
1049 {
1050 *(destination) = *(source++);
1051 if ((--i) == 0)
1052 break;
1053 destination++;
1054 } while (1);
1055
1056 /* Copy the second half of the message. */
1057 destination = pipe -> pi_start;
1058 i = (INT) (size - copy_size);
1059 do
1060 {
1061 *(destination++) = *(source);
1062 if ((--i) == 0)
1063 break;
1064 source++;
1065 } while (1);
1066 }
1067 }
1068
1069 /* Check again for wrap-around condition on the write pointer. */
1070 if (destination >= pipe -> pi_end)
1071
1072 /* Move the write pointer to the top of the pipe area. */
1073 destination = pipe -> pi_start;
1074
1075 /* Determine if the pipe supports variable-length messages. If
1076 so, pad bytes are needed to keep UNSIGNED alignment. */
1077 if (pad)
1078 {
1079
1080 /* Variable-size message. Add pad bytes to the write
1081 pointer. */
1082
1083 /* Calculate the number of bytes remaining from the write
1084 pointer to the bottom of the pipe. */
1085 copy_size = pipe -> pi_end - destination;
1086
1087 /* If there is not enough room at the bottom of the pipe, the
1088 pad bytes must be wrapped around to the top. */
1089 if (copy_size <= pad)
1090
1091 /* Move write pointer to the top of the pipe and make the
1092 necessary adjustment. */
1093 destination = pipe -> pi_start + (pad - copy_size);
1094 else
1095
1096 /* There is enough room in the pipe to simply add the
1097 the pad bytes to the write pointer. */
1098 destination = destination + pad;
1099
1100 /* Decrement the number of available bytes. */
1101 pipe -> pi_available = pipe -> pi_available - pad;
1102 }
1103
1104 /* Update the actual write pointer. */
1105 pipe -> pi_write = destination;
1106
1107 /* Decrement the number of available bytes. */
1108 pipe -> pi_available = pipe -> pi_available - size;
1109
1110 /* Increment the number of messages in the pipe. */
1111 pipe -> pi_messages++;
1112 }
1113 }
1114
1115 /* Release protection against access to the pipe. */
1116 TCT_Unprotect();
1117
1118 /* Return to user mode */
1119 NU_USER_MODE();
1120
1121 /* Return the completion status. */
1122 return(status);
1123 }
1124
1125
1126
1127
1128
1129
1130