⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sema4.c

📁 linux环境支持psos的操作系统。非常适合进行移植的朋友。
💻 C
📖 第 1 页 / 共 3 页
字号:
    }
    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 + -