FreeCalypso > hg > fc-tourmaline
view src/nucleus/pic.c @ 223:740a8e8fc9d7
startup sync logic rework for the new PWON button boot scheme
Previously we added logic to the MMI task to hold off PEI init until
R2D is running, and then extended that condition to wait for FCHG
init too. However, the dependencies of MMI upon R2D and FCHG don't
start until mmiInit(), and that call is driven by Switch_ON() code,
hence the wait for R2D and FCHG init can be made in that code path
instead of the MMI task. Furthermore, with our new way of signaling
PWON button boot to MMI, we need a new wait to ensure that the MMI
task is up - previously this assurance was provided by the wait for
Kp pointers to be set.
Solution: revert our previous PEI init hold-off additions to MMI,
add a new flag indicating MMI task init done, and put the combined
wait for all needed conditions into our new PWON button boot code
in power.c.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Tue, 27 Apr 2021 06:24:52 +0000 |
parents | 4e78acac3d88 |
children |
line wrap: on
line source
/*************************************************************************/ /* */ /* Copyright Mentor Graphics Corporation 2002 */ /* All Rights Reserved. */ /* */ /* THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS */ /* THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS */ /* SUBJECT TO LICENSE TERMS. */ /* */ /*************************************************************************/ /*************************************************************************/ /* */ /* FILE NAME VERSION */ /* */ /* pic.c Nucleus PLUS 1.14 */ /* */ /* COMPONENT */ /* */ /* PI - Pipe Management */ /* */ /* DESCRIPTION */ /* */ /* This file contains the core routines for the pipe management */ /* component. */ /* */ /* DATA STRUCTURES */ /* */ /* None */ /* */ /* FUNCTIONS */ /* */ /* PIC_Create_Pipe Create a message pipe */ /* PIC_Delete_Pipe Delete a message pipe */ /* PIC_Send_To_Pipe Send message to a pipe */ /* PIC_Receive_From_Pipe Receive a message from pipe */ /* PIC_Cleanup Cleanup on timeout or a */ /* terminate condition */ /* */ /* DEPENDENCIES */ /* */ /* cs_extr.h Common Service functions */ /* tc_extr.h Thread Control functions */ /* pi_extr.h Pipe functions */ /* hi_extr.h History functions */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 08-09-1993 Corrected pointer retrieval */ /* loop, resulting in version 1.0a */ /* 08-09-1993 Verified version 1.0a */ /* 03-01-1994 Moved non-core functions into */ /* supplemental files, changed */ /* function interfaces to match */ /* those in prototype, added */ /* register options, changed */ /* protection logic to reduce */ /* overhead, corrected bug in */ /* pipe reset, optimized item */ /* copy loops, resulting in */ /* version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* 04-17-1996 updated to version 1.2 */ /* 03-24-1998 Released version 1.3 */ /* 03-26-1999 Released 1.11m (new release */ /* numbering scheme) */ /* 04-17-2002 Released version 1.13m */ /* 11-07-2002 Released version 1.14 */ /*************************************************************************/ #define NU_SOURCE_FILE #include "cs_extr.h" /* Common service functions */ #include "tc_extr.h" /* Thread control functions */ #include "pi_extr.h" /* Pipe functions */ #include "hi_extr.h" /* History functions */ #include "profiler.h" /* ProView interface */ /* Define external inner-component global data references. */ extern CS_NODE *PID_Created_Pipes_List; extern UNSIGNED PID_Total_Pipes; extern TC_PROTECT PID_List_Protect; /* Define internal component function prototypes. */ VOID PIC_Cleanup(VOID *information); /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* PIC_Create_Pipe */ /* */ /* DESCRIPTION */ /* */ /* This function creates a pipe and then places it on the list */ /* of created pipes. */ /* */ /* CALLED BY */ /* */ /* Application */ /* PICE_Create_Pipe Error checking shell */ /* */ /* CALLS */ /* */ /* CSC_Place_On_List Add to node to linked-list */ /* [HIC_Make_History_Entry] Make entry in history log */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Protect Data structure protect */ /* TCT_Unprotect Un-protect data structure */ /* */ /* INPUTS */ /* */ /* pipe_ptr Pipe control block pointer */ /* name Pipe name */ /* start_address Starting address of actual */ /* pipe area */ /* pipe_size Total size of pipe in bytes */ /* message_type Type of message supported by */ /* the pipe (fixed/variable) */ /* message_size Size of message. Variable */ /* message-length pipes, this */ /* represents the maximum size*/ /* suspend_type Suspension type */ /* */ /* OUTPUTS */ /* */ /* NU_SUCCESS */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 03-01-1994 Changed function interfaces to */ /* match those in prototype, */ /* added register options, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ STATUS PIC_Create_Pipe(NU_PIPE *pipe_ptr, CHAR *name, VOID *start_address, UNSIGNED pipe_size, OPTION message_type, UNSIGNED message_size, OPTION suspend_type) { R1 PI_PCB *pipe; /* Pipe control block ptr */ INT i; /* Working index variable */ NU_SUPERV_USER_VARIABLES /* Switch to supervisor mode */ NU_SUPERVISOR_MODE(); /* Move input pipe pointer into internal pointer. */ pipe = (PI_PCB *) pipe_ptr; #ifdef NU_ENABLE_STACK_CHECK /* Call stack checking function to check for an overflow condition. */ TCT_Check_Stack(); #endif #ifdef NU_ENABLE_HISTORY /* Make an entry that corresponds to this function in the system history log. */ HIC_Make_History_Entry(NU_CREATE_PIPE_ID, (UNSIGNED) pipe, (UNSIGNED) name, (UNSIGNED) start_address); #endif /* First, clear the pipe ID just in case it is an old pipe Control Block. */ pipe -> pi_id = 0; /* Fill in the pipe name. */ for (i = 0; i < NU_MAX_NAME; i++) pipe -> pi_name[i] = name[i]; /* Setup the pipe suspension type. */ if (suspend_type == NU_FIFO) /* FIFO suspension is selected, setup the flag accordingly. */ pipe -> pi_fifo_suspend = NU_TRUE; else /* Priority suspension is selected. */ pipe -> pi_fifo_suspend = NU_FALSE; /* Setup the pipe message type. */ if (message_type == NU_FIXED_SIZE) /* Fixed-size messages are required. */ pipe -> pi_fixed_size = NU_TRUE; else /* Variable-size messages are required. */ pipe -> pi_fixed_size = NU_FALSE; /* Setup the message size. */ pipe -> pi_message_size = message_size; /* Clear the messages counter. */ pipe -> pi_messages = 0; /* Setup the actual pipe pointers. */ pipe -> pi_pipe_size = pipe_size; /* Determine if the pipe's size needs to be adjusted. */ if (pipe -> pi_fixed_size) /* The size of a fixed-size message pipe must be an even multiple of the actual message size. */ pipe_size = (pipe_size/message_size) * message_size; else /* Insure that the size is in terms of UNSIGNED data elements. This insures that the UNSIGNED word is never written past the end of the pipe. */ pipe_size = (pipe_size/sizeof(UNSIGNED)) * sizeof(UNSIGNED); pipe -> pi_available = pipe_size; pipe -> pi_start = (BYTE_PTR) start_address; pipe -> pi_end = pipe -> pi_start + pipe_size; pipe -> pi_read = (BYTE_PTR) start_address; pipe -> pi_write = (BYTE_PTR) start_address; /* Clear the suspension list pointer. */ pipe -> pi_suspension_list = NU_NULL; /* Clear the number of tasks waiting on the pipe counter. */ pipe -> pi_tasks_waiting = 0; /* Clear the urgent message list pointer. */ pipe -> pi_urgent_list = NU_NULL; /* Initialize link pointers. */ pipe -> pi_created.cs_previous = NU_NULL; pipe -> pi_created.cs_next = NU_NULL; /* Protect against access to the list of created pipes. */ TCT_Protect(&PID_List_Protect); /* At this point the pipe is completely built. The ID can now be set and it can be linked into the created pipe list. */ pipe -> pi_id = PI_PIPE_ID; /* Link the pipe into the list of created pipes and increment the total number of pipes in the system. */ CSC_Place_On_List(&PID_Created_Pipes_List, &(pipe -> pi_created)); PID_Total_Pipes++; #ifdef INCLUDE_PROVIEW _RTProf_DumpPipe(RT_PROF_CREATE_PIPE,pipe,RT_PROF_OK); #endif /* INCLUDE_PROVIEW */ /* Release protection against access to the list of created pipes. */ TCT_Unprotect(); /* Return to user mode */ NU_USER_MODE(); /* Return successful completion. */ return(NU_SUCCESS); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* PIC_Delete_Pipe */ /* */ /* DESCRIPTION */ /* */ /* This function deletes a pipe and removes it from the list of */ /* created pipes. All tasks suspended on the pipe are */ /* resumed. Note that this function does not free the memory */ /* associated with the pipe. */ /* */ /* CALLED BY */ /* */ /* Application */ /* PICE_Delete_Pipe Error checking shell */ /* */ /* CALLS */ /* */ /* CSC_Remove_From_List Remove node from list */ /* [HIC_Make_History_Entry] Make entry in history log */ /* TCC_Resume_Task Resume a suspended task */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Control_To_System Transfer control to system */ /* TCT_Protect Protect created list */ /* TCT_Set_Current_Protect Modify current protection */ /* TCT_System_Protect Protect against system access*/ /* TCT_System_Unprotect Release system protection */ /* TCT_Unprotect Release protection */ /* */ /* INPUTS */ /* */ /* pipe_ptr Pipe control block pointer */ /* */ /* OUTPUTS */ /* */ /* NU_SUCCESS */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 03-01-1994 Changed function interfaces to */ /* match those in prototype, */ /* added register options, changed */ /* protection logic to reduce */ /* overhead, resulting in */ /* version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ STATUS PIC_Delete_Pipe(NU_PIPE *pipe_ptr) { R1 PI_PCB *pipe; /* Pipe control block ptr */ PI_SUSPEND *suspend_ptr; /* Suspend block pointer */ PI_SUSPEND *next_ptr; /* Next suspension block ptr */ STATUS preempt; /* Status for resume call */ NU_SUPERV_USER_VARIABLES /* Switch to supervisor mode */ NU_SUPERVISOR_MODE(); /* Move input pipe pointer into internal pointer. */ pipe = (PI_PCB *) pipe_ptr; #ifdef NU_ENABLE_STACK_CHECK /* Call stack checking function to check for an overflow condition. */ TCT_Check_Stack(); #endif #ifdef NU_ENABLE_HISTORY /* Make an entry that corresponds to this function in the system history log. */ HIC_Make_History_Entry(NU_DELETE_PIPE_ID, (UNSIGNED) pipe, (UNSIGNED) 0, (UNSIGNED) 0); #endif /* Protect against access to the pipe. */ TCT_System_Protect(); #ifdef INCLUDE_PROVIEW _RTProf_DumpPipe(RT_PROF_DELETE_PIPE,pipe,RT_PROF_OK); #endif /* INCLUDE_PROVIEW */ /* Clear the pipe ID. */ pipe -> pi_id = 0; /* Release protection. */ TCT_Unprotect(); /* Protect against access to the list of created pipes. */ TCT_Protect(&PID_List_Protect); /* Remove the pipe from the list of created pipes. */ CSC_Remove_From_List(&PID_Created_Pipes_List, &(pipe -> pi_created)); /* Decrement the total number of created pipes. */ PID_Total_Pipes--; /* Pickup the suspended task pointer list. */ suspend_ptr = pipe -> pi_suspension_list; /* Walk the chain task(s) currently suspended on the pipe. */ preempt = 0; while (suspend_ptr) { /* Protect against system access. */ TCT_System_Protect(); /* Resume the suspended task. Insure that the status returned is NU_PIPE_DELETED. */ suspend_ptr -> pi_return_status = NU_PIPE_DELETED; /* Point to the next suspend structure in the link. */ next_ptr = (PI_SUSPEND *) (suspend_ptr -> pi_suspend_link.cs_next); /* Resume the specified task. */ preempt = preempt | TCC_Resume_Task((NU_TASK *) suspend_ptr -> pi_suspended_task, NU_PIPE_SUSPEND); /* Determine if the next is the same as the head pointer. */ if (next_ptr == pipe -> pi_suspension_list) /* Clear the suspension pointer to signal the end of the list traversal. */ suspend_ptr = NU_NULL; else /* Setup the next suspension pointer. */ suspend_ptr = next_ptr; /* Modify current protection. */ TCT_Set_Current_Protect(&PID_List_Protect); /* Clear the system protection. */ TCT_System_Unprotect(); } /* Pickup the urgent message suspension list. */ suspend_ptr = pipe -> pi_urgent_list; /* Walk the chain task(s) currently suspended on the pipe. */ while (suspend_ptr) { /* Protect against system access. */ TCT_System_Protect(); /* Resume the suspended task. Insure that the status returned is NU_PIPE_DELETED. */ suspend_ptr -> pi_return_status = NU_PIPE_DELETED; /* Point to the next suspend structure in the link. */ next_ptr = (PI_SUSPEND *) (suspend_ptr -> pi_suspend_link.cs_next); /* Resume the specified task. */ preempt = preempt | TCC_Resume_Task((NU_TASK *) suspend_ptr -> pi_suspended_task, NU_PIPE_SUSPEND); /* Determine if the next is the same as the head pointer. */ if (next_ptr == pipe -> pi_urgent_list) /* Clear the suspension pointer to signal the end of the list traversal. */ suspend_ptr = NU_NULL; else /* Position suspend pointer to the next block. */ suspend_ptr = next_ptr; /* Modify current protection. */ TCT_Set_Current_Protect(&PID_List_Protect); /* Clear the system protection. */ TCT_System_Unprotect(); } /* Determine if preemption needs to occur. */ if (preempt) /* Transfer control to system to facilitate preemption. */ TCT_Control_To_System(); /* Release protection against access to the list of created pipes. */ TCT_Unprotect(); /* Return to user mode */ NU_USER_MODE(); /* Return a successful completion. */ return(NU_SUCCESS); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* PIC_Send_To_Pipe */ /* */ /* DESCRIPTION */ /* */ /* This function sends a message to the specified pipe. The */ /* message length is determined by the caller. If there are one */ /* or more tasks suspended on the pipe for a message, the message */ /* is copied into the message area of the first waiting task. If */ /* the task's request is satisfied, it is resumed. Otherwise, if */ /* the pipe cannot hold the message, suspension of the calling */ /* task is an option of the caller. */ /* */ /* CALLED BY */ /* */ /* Application */ /* PICE_Send_To_Pipe Error checking shell */ /* */ /* CALLS */ /* */ /* CSC_Place_On_List Place on suspend list */ /* CSC_Priority_Place_On_List Place on priority list */ /* CSC_Remove_From_List Remove from suspend list */ /* [HIC_Make_History_Entry] Make entry in history log */ /* TCC_Resume_Task Resume a suspended task */ /* TCC_Suspend_Task Suspend calling task */ /* TCC_Task_Priority Pickup task's priority */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Control_To_System Transfer control to system */ /* TCT_Current_Thread Pickup current thread pointer*/ /* TCT_System_Protect Protect pipe */ /* TCT_Unprotect Release protection */ /* */ /* INPUTS */ /* */ /* pipe_ptr Pipe control block pointer */ /* message Pointer to message to send */ /* size Size of message to send */ /* suspend Suspension option if full */ /* */ /* OUTPUTS */ /* */ /* NU_SUCCESS If service is successful */ /* NU_PIPE_FULL If pipe is currently full */ /* NU_TIMEOUT If timeout on service expires*/ /* NU_PIPE_DELETED If pipe was deleted during */ /* suspension */ /* NU_PIPE_RESET If pipe was reset during */ /* suspension */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 03-01-1994 Changed function interfaces to */ /* match those in prototype, */ /* added register options, changed */ /* protection logic to reduce */ /* overhead, optimized copy loop, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ STATUS PIC_Send_To_Pipe(NU_PIPE *pipe_ptr, VOID *message, UNSIGNED size, UNSIGNED suspend) { R1 PI_PCB *pipe; /* Pipe control block ptr */ PI_SUSPEND suspend_block; /* Allocate suspension block */ PI_SUSPEND *suspend_ptr; /* Pointer to suspend block */ R2 BYTE_PTR source; /* Pointer to source */ R3 BYTE_PTR destination; /* Pointer to destination */ UNSIGNED copy_size; /* Partial copy size */ R4 INT i; /* Working counter */ UNSIGNED pad = 0; /* Number of pad bytes */ TC_TCB *task; /* Task pointer */ STATUS preempt; /* Preempt flag */ STATUS status; /* Completion status */ NU_SUPERV_USER_VARIABLES /* Switch to supervisor mode */ NU_SUPERVISOR_MODE(); /* Move input pipe pointer into internal pointer. */ pipe = (PI_PCB *) pipe_ptr; #ifdef NU_ENABLE_STACK_CHECK /* Call stack checking function to check for an overflow condition. */ TCT_Check_Stack(); #endif #ifdef NU_ENABLE_HISTORY /* Make an entry that corresponds to this function in the system history log. */ HIC_Make_History_Entry(NU_SEND_TO_PIPE_ID, (UNSIGNED) pipe, (UNSIGNED) message, (UNSIGNED) size); #endif /* Initialize the status as successful. */ status = NU_SUCCESS; /* Protect against simultaneous access to the pipe. */ TCT_System_Protect(); /* Determine if an extra word of overhead needs to be added to the calculation. */ if (pipe -> pi_fixed_size) /* No overhead. */ i = 0; else { /* Variable messages have one additional word of overhead. */ i = sizeof(UNSIGNED); /* Calculate the number of pad bytes necessary to make keep the pipe write pointer on an UNSIGNED data element alignment. */ pad = (((size + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) * sizeof(UNSIGNED)) - size; /* Insure that padding is included in the overhead. */ i = i + ((INT) pad); /* Make special check to see if a suspension needs to be forced for a variable length message. */ if ((pipe -> pi_suspension_list) && (pipe -> pi_messages)) { /* Pickup task control block pointer. */ task = (TC_TCB *) TCT_Current_Thread(); /* Now we know that there are other task(s) are suspended trying to send a variable length message. Determine whether or not a suspension should be forced. */ if ((pipe -> pi_fifo_suspend) || (suspend == NU_NO_SUSPEND) || ((pipe -> pi_suspension_list) -> pi_suspend_link.cs_priority <= TCC_Task_Priority(task))) /* Bump the computed size to avoid placing the new variable length message ahead of the suspended tasks. */ i = (INT) pipe -> pi_available; } } /* Determine if there is enough room in the pipe for the message. */ if (pipe -> pi_available < (size + i)) { /* pipe does not have room for the message. Determine if suspension is required. */ if (suspend) { /* Suspension is requested. */ /* Increment the number of tasks waiting. */ pipe -> pi_tasks_waiting++; #ifdef INCLUDE_PROVIEW _RTProf_DumpPipe(RT_PROF_SEND_TO_PIPE,pipe,RT_PROF_WAIT); #endif /* INCLUDE_PROVIEW */ /* Setup the suspend block and suspend the calling task. */ suspend_ptr = &suspend_block; suspend_ptr -> pi_pipe = pipe; suspend_ptr -> pi_suspend_link.cs_next = NU_NULL; suspend_ptr -> pi_suspend_link.cs_previous= NU_NULL; suspend_ptr -> pi_message_area = (BYTE_PTR) message; suspend_ptr -> pi_message_size = size; task = (TC_TCB *) TCT_Current_Thread(); suspend_ptr -> pi_suspended_task = task; /* Determine if priority or FIFO suspension is associated with the pipe. */ if (pipe -> pi_fifo_suspend) { /* FIFO suspension is required. Link the suspend block into the list of suspended tasks on this pipe. */ CSC_Place_On_List((CS_NODE **) &(pipe -> pi_suspension_list), &(suspend_ptr -> pi_suspend_link)); } else { /* Get the priority of the current thread so the suspend block can be placed in the appropriate place. */ suspend_ptr -> pi_suspend_link.cs_priority = TCC_Task_Priority(task); CSC_Priority_Place_On_List((CS_NODE **) &(pipe -> pi_suspension_list), &(suspend_ptr -> pi_suspend_link)); } /* Finally, suspend the calling task. Note that the suspension call automatically clears the protection on the pipe. */ TCC_Suspend_Task((NU_TASK *) task, NU_PIPE_SUSPEND, PIC_Cleanup, suspend_ptr, suspend); /* Pickup the return status. */ status = suspend_ptr -> pi_return_status; } else { /* Return a status of NU_PIPE_FULL because there is no room in the pipe for the message. */ status = NU_PIPE_FULL; #ifdef INCLUDE_PROVIEW _RTProf_DumpPipe(RT_PROF_SEND_TO_PIPE,pipe,RT_PROF_FAIL); #endif /* INCLUDE_PROVIEW */ } } else { /* Determine if a task is waiting on an empty pipe. */ if ((pipe -> pi_suspension_list) && (pipe -> pi_messages == 0)) { /* Task is waiting on pipe for a message. */ /* Decrement the number of tasks waiting on pipe. */ pipe -> pi_tasks_waiting--; #ifdef INCLUDE_PROVIEW _RTProf_DumpPipe(RT_PROF_SEND_TO_PIPE,pipe,RT_PROF_OK); #endif /* INCLUDE_PROVIEW */ /* Remove the first suspended block from the list. */ suspend_ptr = pipe -> pi_suspension_list; CSC_Remove_From_List((CS_NODE **) &(pipe -> pi_suspension_list), &(suspend_ptr -> pi_suspend_link)); /* Setup the source and destination pointers. */ source = (BYTE_PTR) message; destination = suspend_ptr -> pi_message_area; /* Initialize the return status. */ suspend_ptr -> pi_return_status = NU_SUCCESS; /* Loop to actually copy the message. */ i = (INT) size; do { *(destination++) = *(source); if ((--i) == 0) break; source++; } while(1); /* Return the size of the message copied. */ suspend_ptr -> pi_actual_size = size; /* Wakeup the waiting task and check for preemption. */ preempt = TCC_Resume_Task((NU_TASK *) suspend_ptr -> pi_suspended_task, NU_PIPE_SUSPEND); /* Determine if preemption needs to take place. */ if (preempt) /* Transfer control to the system if the resumed task function detects a preemption condition. */ TCT_Control_To_System(); } else { /* There is enough room in the pipe and no task is waiting. */ /* Setup the source pointer. */ source = (BYTE_PTR) message; destination = pipe -> pi_write; /* Process according to the type of message supported. */ if (pipe -> pi_fixed_size) { /* Fixed-size messages are supported by this pipe. */ /* Loop to copy the message into the pipe area. */ i = (INT) size; do { *(destination++) = *(source); if ((--i) == 0) break; source++; } while (1); } else { /* Variable-size messages are supported. Processing must check for pipe wrap-around conditions. */ /* Place message size in first location. */ *((UNSIGNED *) destination) = size; destination = destination + sizeof(UNSIGNED); /* Check for a wrap-around condition on the pipe. */ if (destination >= pipe -> pi_end) /* Wrap the write pointer back to the top of the pipe area. */ destination = pipe -> pi_start; /* Decrement the number of bytes remaining for this extra word of overhead. */ pipe -> pi_available = pipe -> pi_available - sizeof(UNSIGNED); /* Calculate the number of bytes remaining from the write pointer to the bottom of the pipe. */ copy_size = pipe -> pi_end - destination; /* Determine if the message needs to be wrapped around the edge of the pipe area. */ if (copy_size >= size) { /* Copy the whole message at once. */ i = (INT) size; do { *(destination++) = *(source); if ((--i) == 0) break; source++; } while (1); } else { /* Copy the first half of the message. */ i = (INT) copy_size; do { *(destination) = *(source++); if ((--i) == 0) break; destination++; } while (1); /* Copy the second half of the message. */ destination = pipe -> pi_start; i = (INT) (size - copy_size); do { *(destination++) = *(source); if ((--i) == 0) break; source++; } while (1); } } /* Check again for wrap-around condition on the write pointer. */ if (destination >= pipe -> pi_end) /* Move the write pointer to the top of the pipe area. */ destination = pipe -> pi_start; /* Determine if the pipe supports variable-length messages. If so, pad bytes are needed to keep UNSIGNED alignment. */ if (pad) { /* Variable-size message. Add pad bytes to the write pointer. */ /* Calculate the number of bytes remaining from the write pointer to the bottom of the pipe. */ copy_size = pipe -> pi_end - destination; /* If there is not enough room at the bottom of the pipe, the pad bytes must be wrapped around to the top. */ if (copy_size <= pad) /* Move write pointer to the top of the pipe and make the necessary adjustment. */ destination = pipe -> pi_start + (pad - copy_size); else /* There is enough room in the pipe to simply add the the pad bytes to the write pointer. */ destination = destination + pad; /* Decrement the number of available bytes. */ pipe -> pi_available = pipe -> pi_available - pad; } /* Update the actual write pointer. */ pipe -> pi_write = destination; /* Decrement the number of available bytes. */ pipe -> pi_available = pipe -> pi_available - size; /* Increment the number of messages in the pipe. */ pipe -> pi_messages++; #ifdef INCLUDE_PROVIEW _RTProf_DumpPipe(RT_PROF_SEND_TO_PIPE,pipe,RT_PROF_OK); #endif /* INCLUDE_PROVIEW */ } } /* Release protection against access to the pipe. */ TCT_Unprotect(); /* Return to user mode */ NU_USER_MODE(); /* Return the completion status. */ return(status); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* PIC_Receive_From_Pipe */ /* */ /* DESCRIPTION */ /* */ /* This function receives a message from the specified pipe. The */ /* size of the message is specified by the caller. If there is a */ /* message currently in the pipe, the message is removed from the */ /* pipe and placed in the caller's area. Suspension is possible */ /* if the request cannot be satisfied. */ /* */ /* CALLED BY */ /* */ /* Application */ /* PICE_Receive_From_Pipe Error checking shell */ /* */ /* CALLS */ /* */ /* CSC_Place_On_List Place on suspend list */ /* CSC_Remove_From_List Remove from suspend list */ /* [HIC_Make_History_Entry] Make entry in history log */ /* TCC_Resume_Task Resume a suspended task */ /* TCC_Suspend_Task Suspend calling task */ /* TCC_Task_Priority Pickup task's priority */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Control_To_System Transfer control to system */ /* TCT_Current_Thread Pickup current thread pointer*/ /* TCT_System_Protect Protect pipe */ /* TCT_Unprotect Release protection */ /* */ /* INPUTS */ /* */ /* pipe_ptr Pipe control block pointer */ /* message Pointer to message to send */ /* size Size of the message */ /* actual_size Size of message received */ /* suspend Suspension option if empty */ /* */ /* OUTPUTS */ /* */ /* NU_SUCCESS If service is successful */ /* NU_PIPE_EMPTY If pipe is currently empty */ /* NU_TIMEOUT If timeout on service expires*/ /* NU_PIPE_DELETED If pipe was deleted during */ /* suspension */ /* NU_PIPE_RESET If pipe was reset during */ /* suspension */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* 03-01-1994 Changed function interfaces to */ /* match those in prototype, */ /* added register options, changed */ /* protection logic to reduce */ /* overhead, optimized copy loop, */ /* resulting in version 1.1 */ /* */ /* 03-18-1994 Verified version 1.1 */ /* */ /*************************************************************************/ STATUS PIC_Receive_From_Pipe(NU_PIPE *pipe_ptr, VOID *message, UNSIGNED size, UNSIGNED *actual_size, UNSIGNED suspend) { R1 PI_PCB *pipe; /* Pipe control block ptr */ PI_SUSPEND suspend_block; /* Allocate suspension block */ PI_SUSPEND *suspend_ptr; /* Pointer to suspend block */ R2 BYTE_PTR source; /* Pointer to source */ R3 BYTE_PTR destination; /* Pointer to destination */ TC_TCB *task; /* Task pointer */ UNSIGNED copy_size; /* Number of bytes to copy */ UNSIGNED pad = 0; /* Number of pad bytes */ R4 INT i; /* Working counter */ STATUS preempt; /* Preemption flag */ STATUS status; /* Completion status */ NU_SUPERV_USER_VARIABLES /* Switch to supervisor mode */ NU_SUPERVISOR_MODE(); /* Move input pipe pointer into internal pointer. */ pipe = (PI_PCB *) pipe_ptr; #ifdef NU_ENABLE_STACK_CHECK /* Call stack checking function to check for an overflow condition. */ TCT_Check_Stack(); #endif #ifdef NU_ENABLE_HISTORY /* Make an entry that corresponds to this function in the system history log. */ HIC_Make_History_Entry(NU_RECEIVE_FROM_PIPE_ID, (UNSIGNED) pipe, (UNSIGNED) message, (UNSIGNED) size); #endif /* Initialize the status as successful. */ status = NU_SUCCESS; /* Protect against simultaneous access to the pipe. */ TCT_System_Protect(); /* Determine if an urgent message request is currently suspended. */ if (pipe -> pi_urgent_list) { /* If so, copy the message from the suspended request block and resume the associated task. */ /* Decrement the number of tasks waiting on pipe. */ pipe -> pi_tasks_waiting--; /* Remove the first suspended block from the list. */ suspend_ptr = pipe -> pi_urgent_list; CSC_Remove_From_List((CS_NODE **) &(pipe -> pi_urgent_list), &(suspend_ptr -> pi_suspend_link)); /* Setup the source and destination pointers. */ destination = (BYTE_PTR) message; source = suspend_ptr -> pi_message_area; /* Initialize the return status. */ suspend_ptr -> pi_return_status = NU_SUCCESS; /* Loop to actually copy the message. */ i = (INT) size; do { *(destination++) = *(source); if ((--i) == 0) break; source++; } while (1); /* Return the size of the message copied. */ *actual_size = suspend_ptr -> pi_message_size; /* Wakeup the waiting task and check for preemption. */ preempt = TCC_Resume_Task((NU_TASK *) suspend_ptr -> pi_suspended_task, NU_PIPE_SUSPEND); /* Determine if preemption needs to take place. */ if (preempt) /* Transfer control to the system if the resumed task function detects a preemption condition. */ TCT_Control_To_System(); } /* Determine if there are messages in the pipe. */ else if (pipe -> pi_messages) { /* Copy message from pipe into the caller's area. */ /* Setup the source and destination pointers. */ destination = (BYTE_PTR) message; source = pipe -> pi_read; /* Process according to the type of message supported by the pipe. */ if (pipe -> pi_fixed_size) { /* Pipe supports fixed-size messages. */ /* Copy the message from the pipe area into the destination. */ i = (INT) size; do { *(destination) = *(source++); if ((--i) == 0) break; destination++; } while (1); } else { /* Pipe supports variable-size messages. */ /* Variable length message size is actually in the pipe area. */ size = *((UNSIGNED *) source); source = source + sizeof(UNSIGNED); /* Check for a wrap-around condition on the pipe. */ if (source >= pipe -> pi_end) /* Wrap the read pointer back to the top of the pipe area. */ source = pipe -> pi_start; /* Increment the number of available bytes in the pipe. */ pipe -> pi_available = pipe -> pi_available + sizeof(UNSIGNED); /* Calculate the number of pad bytes necessary to keep the pipe read pointer on an UNSIGNED data element alignment.*/ pad = (((size + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) * sizeof(UNSIGNED)) - size; /* Calculate the number of bytes remaining from the read pointer to the bottom of the pipe. */ copy_size = pipe -> pi_end - source; /* Determine if the message needs to be wrapped around the edge of the pipe area. */ if (copy_size >= size) { /* Copy the whole message at once. */ i = (INT) size; do { *(destination) = *(source++); if ((--i) == 0) break; destination++; } while (1); } else { /* Copy the first half of the message. */ i = (INT) copy_size; do { *(destination++) = *(source); if ((--i) == 0) break; source++; } while (1); /* Copy the second half of the message. */ source = pipe -> pi_start; i = (INT) (size - copy_size); do { *(destination) = *(source++); if ((--i) == 0) break; destination++; } while (1); } } /* Check again for wrap-around condition on the read pointer. */ if (source >= pipe -> pi_end) /* Move the read pointer to the top of the pipe area. */ source = pipe -> pi_start; /* Determine if the pipe supports variable-length messages. If so, pad bytes are needed to keep UNSIGNED alignment. */ if (pad) { /* Variable-size message. Add pad bytes to the read pointer. */ /* Calculate the number of bytes remaining from the read pointer to the bottom of the pipe. */ copy_size = pipe -> pi_end - source; /* If there is not enough room at the bottom of the pipe, the pad bytes must be wrapped around to the top. */ if (copy_size <= pad) /* Move read pointer to the top of the pipe and make the necessary adjustment. */ source = pipe -> pi_start + (pad - copy_size); else /* There is enough room in the pipe to simply add the the pad bytes to the read pointer. */ source = source + pad; /* Add pad bytes to the available bytes count. */ pipe -> pi_available = pipe -> pi_available + pad; } /* Adjust the actual read pointer. */ pipe -> pi_read = source; /* Increment the number of available bytes. */ pipe -> pi_available = pipe -> pi_available + size; /* Decrement the number of messages in the pipe. */ pipe -> pi_messages--; /* Return the number of bytes received. */ *actual_size = size; #ifdef INCLUDE_PROVIEW _RTProf_DumpPipe(RT_PROF_RECEIVE_FROM_PIPE,pipe,RT_PROF_OK); #endif /* INCLUDE_PROVIEW */ /* Determine if any tasks suspended on a full pipe can be woken up. */ if (pipe -> pi_suspension_list) { /* Pickup the suspension list and examine suspension blocks to see if the message could now fit in the pipe. */ suspend_ptr = pipe -> pi_suspension_list; preempt = NU_FALSE; size = suspend_ptr -> pi_message_size; i = 0; pad = 0; /* Overhead of each pipe message. */ if (!pipe -> pi_fixed_size) { /* Variable messages have one additional word of overhead. */ i = sizeof(UNSIGNED); /* Calculate the number of pad bytes necessary to keep the pipe write pointer on an UNSIGNED data element alignment. */ pad = (((size + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) * sizeof(UNSIGNED)) - size; /* Insure that padding is included in the overhead. */ i = i + ((INT) pad); } while ((suspend_ptr) && ((size + i) <= pipe -> pi_available)) { /* Place the suspended task's message into the pipe. */ /* Setup the source and destination pointers. */ source = suspend_ptr -> pi_message_area; destination = pipe -> pi_write; /* Process according to the type of message supported. */ if (pipe -> pi_fixed_size) { /* Fixed-size messages are supported by this pipe. */ /* Loop to copy the message into the pipe area. */ i = (INT) size; do { *(destination++) = *(source); if ((--i) == 0) break; source++; } while (1); } else { /* Variable-size messages are supported. Processing must check for pipe wrap-around conditions. */ /* Place message size in first location. */ *((UNSIGNED *) destination) = size; destination = destination + sizeof(UNSIGNED); /* Check for a wrap-around condition on the pipe. */ if (destination >= pipe -> pi_end) /* Wrap the write pointer back to the top of the pipe area. */ destination = pipe -> pi_start; /* Decrement the number of bytes remaining for this extra word of overhead. */ pipe -> pi_available = pipe -> pi_available - sizeof(UNSIGNED); /* Calculate the number of bytes remaining from the write pointer to the bottom of the pipe. */ copy_size = pipe -> pi_end - destination; /* Determine if the message needs to be wrapped around the edge of the pipe area. */ if (copy_size >= size) { /* Copy the whole message at once. */ i = (INT) size; do { *(destination++) = *(source); if ((--i) == 0) break; source++; } while (1); } else { /* Copy the first half of the message. */ i = (INT) copy_size; do { *(destination) = *(source++); if ((--i) == 0) break; destination++; } while (1); /* Copy the second half of the message. */ destination = pipe -> pi_start; i = (INT) (size - copy_size); do { *(destination++) = *(source); if ((--i) == 0) break; source++; } while (1); } } /* Check again for wrap-around condition on the write pointer. */ if (destination >= pipe -> pi_end) /* Move the write pointer to the top of the pipe area. */ destination = pipe -> pi_start; /* Determine if the pipe supports variable-length messages. If so, pad bytes are needed to keep UNSIGNED alignment. */ if (pad) { /* Variable-size message. Add pad bytes to the write pointer. */ /* Calculate the number of bytes remaining from the write pointer to the bottom of the pipe. */ copy_size = pipe -> pi_end - destination; /* If there is not enough room at the bottom of the pipe, the pad bytes must be wrapped around to the top. */ if (copy_size <= pad) /* Move write pointer to the top of the pipe and make the necessary adjustment. */ destination = pipe -> pi_start + (pad - copy_size); else /* There is enough room in the pipe to simply add the pad bytes to the write pointer. */ destination = destination + pad; /* Decrement the number of available bytes. */ pipe -> pi_available = pipe -> pi_available - pad; } /* Update the actual write pointer. */ pipe -> pi_write = destination; /* Decrement the number of available bytes. */ pipe -> pi_available = pipe -> pi_available - size; /* Increment the number of messages in the pipe. */ pipe -> pi_messages++; /* Decrement the number of tasks waiting counter. */ pipe -> pi_tasks_waiting--; /* Remove the first suspended block from the list. */ CSC_Remove_From_List((CS_NODE **) &(pipe -> pi_suspension_list), &(suspend_ptr -> pi_suspend_link)); /* Return a successful status. */ suspend_ptr -> pi_return_status = NU_SUCCESS; /* Resume the suspended task. */ preempt = preempt | TCC_Resume_Task((NU_TASK *) suspend_ptr -> pi_suspended_task, NU_PIPE_SUSPEND); /* Setup suspend pointer to the head of the list. */ suspend_ptr = pipe -> pi_suspension_list; /* Determine if there really is another suspended block. If there is and the pipe supports variable length messages, calculate new size and padding parameters. */ if ((suspend_ptr) && (!pipe -> pi_fixed_size)) { /* Get the next message size. */ size = suspend_ptr -> pi_message_size; /* Variable messages have one additional word of overhead. */ i = sizeof(UNSIGNED); /* Calculate the number of pad bytes necessary to keep the pipe write pointer on an UNSIGNED data element alignment. */ pad = (((size + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) * sizeof(UNSIGNED)) - size; /* Insure that padding is included in the overhead. */ i = i + ((INT) pad); } } /* Determine if a preempt condition is present. */ if (preempt) /* Transfer control to the system if the resumed task function detects a preemption condition. */ TCT_Control_To_System(); } } else { /* pipe is empty. Determine if the task wants to suspend. */ if (suspend) { /* Increment the number of tasks waiting on the pipe counter. */ pipe -> pi_tasks_waiting++; #ifdef INCLUDE_PROVIEW _RTProf_DumpPipe(RT_PROF_RECEIVE_FROM_PIPE,pipe,RT_PROF_WAIT); #endif /* INCLUDE_PROVIEW */ /* Setup the suspend block and suspend the calling task. */ suspend_ptr = &suspend_block; suspend_ptr -> pi_pipe = pipe; suspend_ptr -> pi_suspend_link.cs_next = NU_NULL; suspend_ptr -> pi_suspend_link.cs_previous = NU_NULL; suspend_ptr -> pi_message_area = (BYTE_PTR) message; suspend_ptr -> pi_message_size = size; task = (TC_TCB *) TCT_Current_Thread(); suspend_ptr -> pi_suspended_task = task; /* Determine if priority or FIFO suspension is associated with the pipe. */ if (pipe -> pi_fifo_suspend) { /* FIFO suspension is required. Link the suspend block into the list of suspended tasks on this pipe. */ CSC_Place_On_List((CS_NODE **) &(pipe -> pi_suspension_list), &(suspend_ptr -> pi_suspend_link)); } else { /* Get the priority of the current thread so the suspend block can be placed in the appropriate place. */ suspend_ptr -> pi_suspend_link.cs_priority = TCC_Task_Priority(task); CSC_Priority_Place_On_List((CS_NODE **) &(pipe -> pi_suspension_list), &(suspend_ptr -> pi_suspend_link)); } /* Finally, suspend the calling task. Note that the suspension call automatically clears the protection on the pipe. */ TCC_Suspend_Task((NU_TASK *) task, NU_PIPE_SUSPEND, PIC_Cleanup, suspend_ptr, suspend); /* Pickup the status of the request. */ status = suspend_ptr -> pi_return_status; *actual_size = suspend_ptr -> pi_actual_size; } else { /* Return a status of NU_PIPE_EMPTY because there are no messages in the pipe. */ status = NU_PIPE_EMPTY; #ifdef INCLUDE_PROVIEW _RTProf_DumpPipe(RT_PROF_RECEIVE_FROM_PIPE,pipe,RT_PROF_FAIL); #endif /* INCLUDE_PROVIEW */ } } /* Release protection against access to the pipe. */ TCT_Unprotect(); /* Return to user mode */ NU_USER_MODE(); /* Return the completion status. */ return(status); } /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* PIC_Cleanup */ /* */ /* DESCRIPTION */ /* */ /* This function is responsible for removing a suspension block */ /* from a pipe. It is not called unless a timeout or a task */ /* terminate is in progress. Note that protection is already in */ /* effect - the same protection at suspension time. This routine */ /* must be called from Supervisor mode in Supervisor/User mode */ /* switching kernels. */ /* */ /* CALLED BY */ /* */ /* TCC_Timeout Task timeout */ /* TCC_Terminate Task terminate */ /* */ /* CALLS */ /* */ /* CSC_Remove_From_List Remove suspend block from */ /* the suspension list */ /* */ /* INPUTS */ /* */ /* information Pointer to suspend block */ /* */ /* OUTPUTS */ /* */ /* None */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 03-01-1993 Created initial version 1.0 */ /* 04-19-1993 Verified version 1.0 */ /* */ /*************************************************************************/ VOID PIC_Cleanup(VOID *information) { PI_SUSPEND *suspend_ptr; /* Suspension block pointer */ NU_SUPERV_USER_VARIABLES /* Switch to supervisor mode */ NU_SUPERVISOR_MODE(); /* Use the information pointer as a suspend pointer. */ suspend_ptr = (PI_SUSPEND *) information; /* By default, indicate that the service timed-out. It really does not matter if this function is called from a terminate request since the task does not resume. */ suspend_ptr -> pi_return_status = NU_TIMEOUT; /* Decrement the number of tasks waiting counter. */ (suspend_ptr -> pi_pipe) -> pi_tasks_waiting--; /* Determine if the suspend block is one the urgent list. */ if ((suspend_ptr -> pi_pipe) -> pi_urgent_list) { /* Unlink the suspend block from the urgent list. */ CSC_Remove_From_List((CS_NODE **) &((suspend_ptr -> pi_pipe) -> pi_urgent_list), &(suspend_ptr -> pi_suspend_link)); } else { /* Unlink the suspend block from the suspension list. */ CSC_Remove_From_List((CS_NODE **) &((suspend_ptr -> pi_pipe) -> pi_suspension_list), &(suspend_ptr -> pi_suspend_link)); } /* Return to user mode */ NU_USER_MODE(); }