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