📄 task.c
字号:
#ifdef DIAG_PRINTFS printf( "\r\nadd susp_tcb @ %p to list @ %p", new_entry, list_head );#endif } /* ** Initialize the suspended task's pointer back to suspend list ** This is used for cleanup during task deletion by t_delete(). */ new_entry->suspend_list = list_head; pthread_mutex_unlock( &task_list_lock ); pthread_cleanup_pop( 0 ); }}/******************************************************************************* unlink_susp_tcb - removes tcb pointer from a linked list of tcb pointers** for tasks suspended on the object owning the list.*****************************************************************************/void unlink_susp_tcb( p2pthread_cb_t **list_head, p2pthread_cb_t *entry ){ p2pthread_cb_t *current_tcb; if ( list_head != (p2pthread_cb_t **)NULL ) { pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock, (void *)&task_list_lock ); pthread_mutex_lock( &task_list_lock ); if ( *list_head == entry ) { *list_head = entry->nxt_susp;#ifdef DIAG_PRINTFS printf( "\r\ndel susp_tcb @ %p from list @ %p - newlist head %p", entry, list_head, *list_head );#endif } else { for ( current_tcb = *list_head; current_tcb != (p2pthread_cb_t *)NULL; current_tcb = current_tcb->nxt_susp ) { if ( current_tcb->nxt_susp == entry ) { current_tcb->nxt_susp = entry->nxt_susp;#ifdef DIAG_PRINTFS printf( "\r\ndel susp_tcb @ %p from list @ %p", entry, current_tcb );#endif } } } entry->nxt_susp = (p2pthread_cb_t *)NULL; pthread_mutex_unlock( &task_list_lock ); pthread_cleanup_pop( 0 ); }}/******************************************************************************* signal_for_my_task - searches the specified 'pended task list' for the** task to be selected according to the specified** pend order. If the selected task is the currently** executing task, the task is deleted from the** specified pended task list and returns a non-zero** result... otherwise the pended task list is not** modified and a zero result is returned.*****************************************************************************/int signal_for_my_task( p2pthread_cb_t **list_head, int pend_order ){ p2pthread_cb_t *signalled_task; p2pthread_cb_t *current_tcb; int result; result = FALSE;#ifdef DIAG_PRINTFS printf( "\r\nsignal_for_my_task - list head = %p", *list_head );#endif if ( list_head != (p2pthread_cb_t **)NULL ) { signalled_task = *list_head; /* ** First determine which task is being signalled */ if ( pend_order != 0 ) { /* ** Tasks pend in priority order... locate the highest priority ** task in the pended list. */ for ( current_tcb = *list_head; current_tcb != (p2pthread_cb_t *)NULL; current_tcb = current_tcb->nxt_susp ) { if ( (current_tcb->prv_priority).sched_priority > (signalled_task->prv_priority).sched_priority ) signalled_task = current_tcb;#ifdef DIAG_PRINTFS printf( "\r\nsignal_for_my_task - tcb @ %p priority %d", current_tcb, (current_tcb->prv_priority).sched_priority );#endif } } /* else ** ** Tasks pend in FIFO order... signal is for task at list head. */ /* ** Signalled task located... see if it's the currently executing task. */ if ( signalled_task == my_tcb() ) { /* ** The currently executing task is being signalled... */ result = TRUE; }#ifdef DIAG_PRINTFS printf( "\r\nsignal_for_my_task - signalled tcb @ %p my tcb @ %p", signalled_task, my_tcb() );#endif } return( result );}/******************************************************************************* new_tid - assigns the next unused task ID for the caller's task*****************************************************************************/static ULONG new_tid( void ){ p2pthread_cb_t *current_tcb; ULONG new_taskid;
/*
** Note: since we only read the task_list, so no locking of
** task_list_lock is needed, and you can't only go to the
** last member in task_list to get it's task_id and plus 1.
*/
/* ** Get the highest previously assigned task id and add one. */ if ( task_list != (p2pthread_cb_t *)NULL ) { /* ** One or more tasks already exist in the task list... ** Find the highest task ID number in the existing list. */ new_taskid = task_list->taskid; for ( current_tcb = task_list; current_tcb->nxt_task != (p2pthread_cb_t *)NULL; current_tcb = current_tcb->nxt_task ) { if ( (current_tcb->nxt_task)->taskid > new_taskid ) { new_taskid = (current_tcb->nxt_task)->taskid; } } /* ** Add one to the highest existing task ID */ new_taskid++; } else { /* ** this is the first task being added to the task list. */ new_taskid = 1; } return( new_taskid );}/******************************************************************************* translate_priority - translates a p2pthread priority into a pthreads priority*****************************************************************************/static int translate_priority( ULONG p2pt_priority, int sched_policy, ULONG *errp ){ int max_priority, min_priority, pthread_priority; /* ** Validate the range of the user's task priority. */ if ( (p2pt_priority < MIN_P2PT_PRIORITY) | (p2pt_priority > MAX_P2PT_PRIORITY) ) *errp = ERR_PRIOR; /* ** Translate the p2pthread priority into a pthreads priority. */ pthread_priority = (int)p2pt_priority; /* ** Next get the allowable priority range for the scheduling policy. */ min_priority = sched_get_priority_min( sched_policy ); max_priority = sched_get_priority_max( sched_policy ); /* ** Now 'clip' the new priority level to within priority range. ** Reserve max_priority level for temporary use during system calls. ** NOTE that relative p2pthread priorities may not translate properly ** if the p2pthread priorities used span several multiples of max_priority. */ pthread_priority %= max_priority; if ( pthread_priority < min_priority ) pthread_priority = min_priority; return( pthread_priority );}/******************************************************************************* tcb_delete - deletes a pthread task control block from the task_list** and frees the memory allocated for the tcb*****************************************************************************/static void tcb_delete( p2pthread_cb_t *tcb ){ p2pthread_cb_t *current_tcb; /* ** If the task_list contains tasks, scan it for a link to the tcb ** being deleted. */ if ( task_list != (p2pthread_cb_t *)NULL ) { /* ** Remove the task from the suspend list for any object it ** is pending on. */ unlink_susp_tcb( tcb->suspend_list, tcb ); pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock, (void *)&task_list_lock ); pthread_mutex_lock( &task_list_lock ); if ( tcb == task_list ) { task_list = tcb->nxt_task; } else { for ( current_tcb = task_list; current_tcb->nxt_task != (p2pthread_cb_t *)NULL; current_tcb = current_tcb->nxt_task ) { if ( tcb == current_tcb->nxt_task ) { /* ** Found the tcb just prior to the one being deleted. ** Unlink the tcb being deleted from the task_list. */ current_tcb->nxt_task = tcb->nxt_task; break; } } } pthread_mutex_unlock( &task_list_lock ); pthread_cleanup_pop( 0 ); } /* Release the memory occupied by the tcb being deleted. */ ts_free( (void *)tcb );}/******************************************************************************* t_delete - removes the specified task(s) from the task list,** frees the memory occupied by the task control block(s),** and kills the pthread(s) associated with the task(s).*****************************************************************************/ULONG t_delete( ULONG tid ){ p2pthread_cb_t *current_tcb; p2pthread_cb_t *self_tcb; ULONG error; error = ERR_NO_ERROR; sched_lock(); self_tcb = my_tcb(); if ( tid == 0 ) { /* ** Delete currently executing task... get its pthread ID */ if ( self_tcb != (p2pthread_cb_t *)NULL ) { /* ** Kill the currently executing task's pthread and ** then de-allocate its data structures. */
/* POSIX threads can exist in either the ‘joinable’ state
** or the ‘detached’ state. A given pthread or process
** can wait for a joinable pthread to terminate. At this time,
** the process or pthread waiting on the terminating pthread
** obtains an exit status from the pthread and then the terminating
** pthread’s resources are released. A ‘detached’pthread has
** effectively been told that no other process or pthread cares when
** it terminates. This means that when the ‘detached’ pthread
** terminates, its resources are released immediately and no other
** process or pthread can receive termination notice or an exit status.
** If the pthread is deleting itself it must be ‘detached’ in order
** to free its Linux resources upon termination.
*/ pthread_detach( self_tcb->pthrid ); pthread_cleanup_push( (void(*)(void *))tcb_delete, (void *)self_tcb ); pthread_exit( ( void *)NULL );
/*
** Because pthread_exit is also a termination point func,
** so the arg of pthread_cleanup_pop is 0, and it's still
** that the function tcb_delete() will be called.
*/ pthread_cleanup_pop( 0 ); } else error = ERR_OBJDEL; } else { /* ** Delete the task whose taskid matches tid. ** If the task_list contains tasks, scan it for the tcb ** whose task id matches the one to be deleted. */ current_tcb = tcb_for( tid ); if ( current_tcb != (p2pthread_cb_t *)NULL ) { /* ** Found the task being deleted... delete it. */ if ( current_tcb != self_tcb ) { /* ** Task being deleted is not the current task. ** Kill the task pthread and wait for it to die. ** Then de-allocate its data structures. */ pthread_cancel( current_tcb->pthrid ); pthread_join( current_tcb->pthrid, (void **)NULL ); tcb_delete( current_tcb ); } else { /* ** Kill the currently executing task's pthread ** and then de-allocate its data structures. */ pthread_detach( self_tcb->pthrid ); pthread_cleanup_push( (void(*)(void *))tcb_delete, (void *)self_tcb ); pthread_exit( ( void *)NULL ); pthread_cleanup_pop( 0 ); } } else error = ERR_OBJDEL; } sched_unlock(); return( error );}/******************************************************************************* cleanup_scheduler_lock ensures that a killed pthread releases the** scheduler lock if it owned it.*****************************************************************************/static void cleanup_scheduler_lock( void *tcb ){ p2pthread_cb_t *mytcb; mytcb = (p2pthread_cb_t *)tcb; pthread_mutex_lock( &p2pt_sched_lock ); if ( scheduler_locked == pthread_self() ) { sched_lock_level = 0; scheduler_locked = (pthread_t)NULL; } pthread_mutex_unlock( &p2pt_sched_lock );}/******************************************************************************* task_wrapper is a pthread used to 'contain' a p2pthread task.*****************************************************************************/static void * task_wrapper( void *arg ){ p2pthread_cb_t *tcb; p2pthread_pb_t *parmblk; void (*task_ptr)( ULONG, ULONG, ULONG, ULONG ); /* ** Make a parameter block pointer from the caller's argument ** Then extract the needed info from the parameter block and ** free its memory before beginning the p2pthread task */ parmblk = (p2pthread_pb_t *)arg; tcb = parmblk->tcb; task_ptr = parmblk->task_ptr; /* ** Note: ensure that this pthread will release the scheduler lock if killed. */ pthread_cleanup_push( cleanup_scheduler_lock, (void *)tcb ); /* ** Call the p2pthread task. Normally this is an endless loop and doesn't ** return here. */#ifdef DIAG_PRINTFS printf( "\r\ntask_wrapper starting task @ %p tcb @ %p:", task_ptr, tcb );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -