📄 sema4.c
字号:
}
else
{
/*
** Semaphore still in service... check for token availability.
** Initially assume no token available for our task
*/
result = 1;
/*
** Multiple posts to the semaphore may be represented by only
** a single signal to the condition variable, so continue
** checking for a token for our task as long as more tokens
** are available.
*/
while ( sem_trywait( &(semaphore->pthread_sema4) ) == 0 )
{
/*
** Available token arrived... see if it's for our task.
*/
if ( (signal_for_my_task( &(semaphore->first_susp),
(semaphore->flags & SM_PRIOR) )) )
{
/*
** Token was destined for our task specifically...
** waiting is over.
*/
result = 0;
*retcode = 0;
break;
}
else
{
/*
** Token isn't for our task...
** Put it back and continue waiting. Sleep awhile to
** allow other tasks ahead of ours in the queue of tasks
** waiting on the semaphore to get their tokens, bringing
** our task to the head of the list.
*/
sem_post( &(semaphore->pthread_sema4) );
pthread_mutex_unlock( &(semaphore->sema4_lock) );
tm_wkafter( 1 );
pthread_mutex_lock( &(semaphore->sema4_lock) );
}
/*
** If a timeout was specified, make sure we respect it and
** exit this loop if it expires.
*/
if ( timeout != (struct timespec *)NULL )
{
gettimeofday( &now, (struct timezone *)NULL );
if ( timeout->tv_nsec > (now.tv_usec * 1000) )
{
usec = (timeout->tv_nsec - (now.tv_usec * 1000)) / 1000;
if ( timeout->tv_sec < now.tv_sec )
usec = 0;
else
usec += ((timeout->tv_sec - now.tv_sec) * 1000000);
}
else
{
usec = ((timeout->tv_nsec + 1000000000) -
(now.tv_usec * 1000)) / 1000;
if ( (timeout->tv_sec - 1) < now.tv_sec )
usec = 0;
else
usec += (((timeout->tv_sec - 1) - now.tv_sec)
* 1000000);
}
if ( usec == 0 )
break;
}
}
}
return( result );
}
/*****************************************************************************
** sm_p - blocks the calling task until a token is available on the
** specified p2pthread semaphore.
*****************************************************************************/
ULONG
sm_p( ULONG smid, ULONG opt, ULONG max_wait )
{
p2pthread_cb_t *our_tcb;
struct timeval now;
struct timespec timeout;
int retcode;
long sec, usec;
p2pt_sema4_t *semaphore;
ULONG error;
error = ERR_NO_ERROR;
if ( (semaphore = smcb_for( smid )) != (p2pt_sema4_t *)NULL )
{
/*
** Lock mutex for semaphore pend
*/
pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
(void *)&(semaphore->sema4_lock));
pthread_mutex_lock( &(semaphore->sema4_lock) );
/*
** Add tcb for task to list of tasks waiting on semaphore
*/
our_tcb = my_tcb();
#ifdef DIAG_PRINTFS
printf( "\r\ntask @ %p wait on semaphore list @ %p", our_tcb,
&(semaphore->first_susp) );
#endif
link_susp_tcb( &(semaphore->first_susp), our_tcb );
retcode = 0;
if ( opt & SM_NOWAIT )
{
/*
** Caller specified no wait on semaphore token...
** Check the condition variable with an immediate timeout.
*/
gettimeofday( &now, (struct timezone *)NULL );
timeout.tv_sec = now.tv_sec;
timeout.tv_nsec = now.tv_usec * 1000;
while ( (waiting_on_sema4( semaphore, &timeout, &retcode )) &&
(retcode != ETIMEDOUT) )
{
retcode = pthread_cond_timedwait( &(semaphore->sema4_send),
&(semaphore->sema4_lock),
&timeout );
}
}
else
{
/*
** Caller expects to wait on semaphore, with or without a timeout.
*/
if ( max_wait == 0L )
{
/*
** Infinite wait was specified... wait without timeout.
*/
while ( waiting_on_sema4( semaphore, 0, &retcode ) )
{
pthread_cond_wait( &(semaphore->sema4_send),
&(semaphore->sema4_lock) );
}
}
else
{
/*
** Wait on semaphore message arrival with timeout...
** Calculate timeout delay in seconds and microseconds.
*/
sec = 0;
usec = max_wait * P2PT_TICK * 1000;
gettimeofday( &now, (struct timezone *)NULL );
usec += now.tv_usec;
if ( usec > 1000000 )
{
sec = usec / 1000000;
usec = usec % 1000000;
}
timeout.tv_sec = now.tv_sec + sec;
timeout.tv_nsec = usec * 1000;
/*
** Wait for a semaphore message for the current task or for the
** timeout to expire. The loop is required since the task
** may be awakened by signals for semaphore tokens which are
** not ours, or for signals other than from a message send.
*/
while ( (waiting_on_sema4( semaphore, &timeout, &retcode )) &&
(retcode != ETIMEDOUT) )
{
retcode = pthread_cond_timedwait( &(semaphore->sema4_send),
&(semaphore->sema4_lock),
&timeout );
}
}
}
/*
** Remove the calling task's tcb from the waiting task list
** for the semaphore.
*/
unlink_susp_tcb( &(semaphore->first_susp), our_tcb );
/*
** See if we were awakened due to a sm_delete on the semaphore.
*/
if ( semaphore->send_type & KILLD )
{
error = ERR_SKILLD;
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) );
/*
** Signal the delete-complete condition variable
** for the semaphore
*/
pthread_cond_broadcast( &(semaphore->smdel_cplt) );
semaphore->send_type = SEND;
/*
** Unlock the semaphore delete completion mutex.
*/
pthread_mutex_unlock( &(semaphore->smdel_lock) );
pthread_cleanup_pop( 0 );
}
#ifdef DIAG_PRINTFS
printf( "...semaphore deleted" );
#endif
}
else
{
/*
** See if we timed out or if we got a token
*/
if ( retcode == ETIMEDOUT )
{
/*
** Timed out without a token
*/
if ( opt & SM_NOWAIT )
{
error = ERR_NOSEM;
#ifdef DIAG_PRINTFS
printf( "...no token available" );
#endif
}
else
{
error = ERR_TIMEOUT;
#ifdef DIAG_PRINTFS
printf( "...timed out" );
#endif
}
}
#ifdef DIAG_PRINTFS
else
{
printf( "...rcvd semaphore token" );
}
#endif
}
/*
** Unlock the mutex for the condition variable and clean up.
*/
pthread_mutex_unlock( &(semaphore->sema4_lock) );
pthread_cleanup_pop( 0 );
}
else
{
error = ERR_OBJDEL; /* Invalid semaphore specified */
}
return( error );
}
/*****************************************************************************
** sm_ident - identifies the specified p2pthread semaphore
*****************************************************************************/
ULONG
sm_ident( char name[4], ULONG node, ULONG *smid )
{
p2pt_sema4_t *current_smcb;
ULONG error;
error = ERR_NO_ERROR;
/*
** Validate the node specifier... only zero is allowed here.
*/
if ( node != 0L )
error = ERR_NODENO;
else
{
/*
** If semaphore name string is a NULL pointer, return with error.
** We'll ASSUME the smid pointer isn't NULL!
*/
if ( name == (char *)NULL )
{
*smid = (ULONG)NULL;
error = ERR_OBJNF;
}
else
{
/*
** Scan the task list for a name matching the caller's name.
*/
for ( current_smcb = sema4_list;
current_smcb != (p2pt_sema4_t *)NULL;
current_smcb = current_smcb->nxt_sema4 )
{
if ( (strncmp( name, current_smcb->sname, 4 )) == 0 )
{
/*
** A matching name was found... return its QID
*/
*smid = current_smcb->smid;
break;
}
}
if ( current_smcb == (p2pt_sema4_t *)NULL )
{
/*
** No matching name found... return caller's QID with error.
*/
*smid = (ULONG)NULL;
error = ERR_OBJNF;
}
}
}
return( error );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -