FreeCalypso > hg > fc-selenite
comparison src/nucleus/pic.c @ 7:0f80e1e4dce4
src/nucleus: library C code import from FreeNucleus package
| author | Mychaela Falconia <falcon@freecalypso.org> | 
|---|---|
| date | Sun, 15 Jul 2018 20:57:33 +0000 | 
| parents | |
| children | 
   comparison
  equal
  deleted
  inserted
  replaced
| 6:8b2a9a374324 | 7:0f80e1e4dce4 | 
|---|---|
| 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 | 
