📄 sema4.c
字号:
#endif
}
else
{
/*
** Scan the next smcb for a matching smid while retaining a
** pointer to the current smcb. If the next smcb matches,
** select it and then unlink it from the semaphore list.
*/
for ( current_smcb = sema4_list;
current_smcb->nxt_sema4 != (p2pt_sema4_t *)NULL;
current_smcb = current_smcb->nxt_sema4 )
{
if ( (current_smcb->nxt_sema4)->smid == smid )
{
/*
** Semaphore ID of next smcb matches...
** Select the smcb and then unlink it by linking
** the selected smcb's next smcb into the current smcb.
*/
selected_smcb = current_smcb->nxt_sema4;
current_smcb->nxt_sema4 = selected_smcb->nxt_sema4;
#ifdef DIAG_PRINTFS
printf( "\r\ndel semaphore cb @ %p from list @ %p",
selected_smcb, current_smcb );
#endif
break;
}
}
}
/*
** Re-enable access to the semaphore list by other threads.
*/
pthread_mutex_unlock( &sema4_list_lock );
pthread_cleanup_pop( 0 );
}
return( selected_smcb );
}
/*****************************************************************************
** sm_create - creates a p2pthread message semaphore
*****************************************************************************/
ULONG
sm_create( char name[4], ULONG count, ULONG opt, ULONG *smid )
{
p2pt_sema4_t *semaphore;
ULONG error;
int i;
char create_error[80];
error = ERR_NO_ERROR;
/*
** First allocate memory for the semaphore control block
*/
semaphore = (p2pt_sema4_t *)ts_malloc( sizeof( p2pt_sema4_t ) );
if ( semaphore != (p2pt_sema4_t *)NULL )
{
/*
** Ok... got a control block. Initialize it.
*/
/*
** Option Flags for semaphore
*/
semaphore->flags = opt;
/*
** ID for semaphore
*/
semaphore->smid = new_smid();
if ( smid != (ULONG *)NULL )
*smid = semaphore->smid;
/*
** Name for semaphore
*/
for ( i = 0; i < 4; i++ )
semaphore->sname[i] = name[i];
#ifdef DIAG_PRINTFS
printf( "\r\nCreating semaphore %c%c%c%c id %ld @ %p",
semaphore->sname[0], semaphore->sname[1],
semaphore->sname[r20], semaphore->sname[3],
semaphore->smid, semaphore );
#endif
/*
** Mutex and Condition variable for semaphore send/pend
*/
pthread_mutex_init( &(semaphore->sema4_lock),
(pthread_mutexattr_t *)NULL );
pthread_cond_init( &(semaphore->sema4_send),
(pthread_condattr_t *)NULL );
/*
** Mutex and Condition variable for semaphore delete/delete
*/
pthread_mutex_init( &(semaphore->smdel_lock),
(pthread_mutexattr_t *)NULL );
pthread_cond_init( &(semaphore->smdel_cplt),
(pthread_condattr_t *)NULL );
/*
** Pthread semaphore used to maintain count. Cause Linuxthread
** didn't inplement the multi-thread shared sema4, so the arg
** 'pshared' should be set to zero, any other value cause the
** function return with -1.
*/
if ( sem_init( &(semaphore->pthread_sema4), 0, (unsigned int)count ) )
{
sprintf( create_error,
"\r\nSemaphore %c%c%c%c creation returned error:",
semaphore->sname[0], semaphore->sname[1],
semaphore->sname[2], semaphore->sname[3] );
perror( create_error );
}
/*
** Type of send operation last performed on semaphore
*/
semaphore->send_type = SEND;
/*
** First task control block in list of tasks waiting on semaphore
*/
semaphore->first_susp = (p2pthread_cb_t *)NULL;
/*
** Link the new semaphore into the semaphore list.
*/
link_smcb( semaphore );
}
else
{
error = ERR_NOSCB;
}
return( error );
}
/*****************************************************************************
** sm_v - releases a p2pthread semaphore token and awakens the first selected
** task waiting on the semaphore.
*****************************************************************************/
ULONG
sm_v( ULONG smid )
{
#ifdef DIAG_PRINTFS
p2pthread_cb_t *our_tcb;
#endif
p2pt_sema4_t *semaphore;
ULONG error;
error = ERR_NO_ERROR;
if ( (semaphore = smcb_for( smid )) != (p2pt_sema4_t *)NULL )
{
#ifdef DIAG_PRINTFS
our_tcb = my_tcb();
printf( "\r\ntask @ %p post to semaphore list @ %p", our_tcb,
&(semaphore->first_susp) );
#endif
/*
** 'Lock the p2pthread scheduler' to defer any context switch to a
** higher priority task until after this call has completed its work.
*/
sched_lock();
/*
** Lock mutex for semaphore send
*/
pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
(void *)&(semaphore->sema4_lock));
pthread_mutex_lock( &(semaphore->sema4_lock) );
sem_post( &(semaphore->pthread_sema4) );
if ( semaphore->first_susp != (p2pthread_cb_t *)NULL )
/*
** Signal the condition variable for the semaphore
*/
pthread_cond_broadcast( &(semaphore->sema4_send) );
/*
** Unlock the semaphore mutex.
*/
pthread_mutex_unlock( &(semaphore->sema4_lock) );
pthread_cleanup_pop( 0 );
/*
** 'Unlock the p2pthread scheduler' to enable a possible context switch
** to a task made runnable by this call.
*/
sched_unlock();
}
else
{
error = ERR_OBJDEL;
}
return( error );
}
/*****************************************************************************
** delete_sema4 - takes care of destroying the specified semaphore and freeing
** any resources allocated for that semaphore
*****************************************************************************/
static void
delete_sema4( p2pt_sema4_t *semaphore )
{
/*
** First remove the semaphore from the semaphore list
*/
unlink_smcb( semaphore->smid );
/*
** Next destroy the pthreads semaphore
*/
sem_destroy( &(semaphore->pthread_sema4) );
/*
** Finally delete the semaphore control block itself;
*/
ts_free( (void *)semaphore );
}
/*****************************************************************************
** sm_delete - removes the specified semaphore from the semaphore list and frees
** the memory allocated for the semaphore control block and extents.
*****************************************************************************/
ULONG
sm_delete( ULONG smid )
{
p2pt_sema4_t *semaphore;
ULONG error;
error = ERR_NO_ERROR;
if ( (semaphore = smcb_for( smid )) != (p2pt_sema4_t *)NULL )
{
/*
** Send signal and block while any tasks are still waiting
** on the semaphore
*/
sched_lock();
if ( semaphore->first_susp != (p2pthread_cb_t *)NULL )
{
/*
** Lock mutex for semaphore delete completion
*/
pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
(void *)&(semaphore->smdel_lock) );
pthread_mutex_lock( &(semaphore->smdel_lock) );
/*
** Lock mutex for semaphore delete
*/
pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
(void *)&(semaphore->sema4_lock));
pthread_mutex_lock( &(semaphore->sema4_lock) );
/*
** Declare the send type
*/
semaphore->send_type = KILLD;
error = ERR_TATSDEL;
/*
** Signal the condition variable for the semaphore
*/
pthread_cond_broadcast( &(semaphore->sema4_send) );
/*
** Unlock the semaphore mutex.
*/
pthread_mutex_unlock( &(semaphore->sema4_lock) );
pthread_cleanup_pop( 0 );
/*
** Wait for all pended tasks to receive delete message.
** The last task to receive the message will signal the
** delete-complete condition variable.
*/
while ( semaphore->first_susp != (p2pthread_cb_t *)NULL )
pthread_cond_wait( &(semaphore->smdel_cplt),
&(semaphore->smdel_lock) );
/*
** Unlock the semaphore delete completion mutex.
*/
pthread_mutex_unlock( &(semaphore->smdel_lock) );
pthread_cleanup_pop( 0 );
}
delete_sema4( semaphore );
sched_unlock();
}
else
{
error = ERR_OBJDEL;
}
return( error );
}
/*****************************************************************************
** waiting_on_sema4 - returns a nonzero result unless a qualifying event
** occurs on the specified semaphore which should cause the
** pended task to be awakened. The qualifying events
** are:
** (1) a message is sent to the semaphore and the current
** task is selected to receive it
** (2) a delete message is sent to the semaphore
** (3) the semaphore is deleted
*****************************************************************************/
static int
waiting_on_sema4( p2pt_sema4_t *semaphore, struct timespec *timeout,
int *retcode )
{
int result;
struct timeval now;
ULONG usec;
if ( semaphore->send_type & KILLD )
{
/*
** Semaphore has been killed... waiting is over.
*/
result = 0;
*retcode = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -