FreeCalypso > hg > freecalypso-citrine
comparison nucleus/pis.c @ 0:75a11d740a02
initial import of gsm-fw from freecalypso-sw rev 1033:5ab737ac3ad7
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 09 Jun 2016 00:02:41 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:75a11d740a02 |
---|---|
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 |