📄 semlib.c
字号:
/***************************************************************************** * semLib.c - defines the wrapper functions and data structures needed * to implement a VxWorks semaphore API in a POSIX Threads * environment. * * Copyright (C) 2000 Monta Vista Software Inc. * * Author : Gary S. Robertson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. ****************************************************************************/#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <signal.h>#include <semaphore.h>#include <sys/time.h>#include "vxwk2pthread.h"#include "vxwkdefs.h"#undef DIAG_PRINTFS#define SEM_OPT_MASK 0x0f#define SEM_TYPE_MASK 0xf0#define BINARY_SEMA4 0x00#define MUTEX_SEMA4 0x10#define COUNTING_SEMA4 0x20#define SEND 0#define FLUSH 1#define KILLD 2/******************************************************************************* Control block for VxWorks semaphore**** The basic POSIX semaphore does not provide for time-bounded waits nor** for selection of a thread to ready based either on FIFO or PRIORITY-based** waiting. This 'wrapper' extends the POSIX pthreads semaphore to include** the attributes of a VxWorks semaphore.*******************************************************************************/typedef struct vxwk_sema4{ /* ** Option and Type Flags for semaphore */ int flags; /* ** Mutex and Condition variable for semaphore post/pend */ pthread_mutex_t sema4_lock; pthread_cond_t sema4_send; /* ** Mutex and Condition variable for semaphore delete */ pthread_mutex_t smdel_lock; pthread_cond_t smdel_cplt; /* ** Count of available 'tokens' for semaphore. */ int token_count; /* ** Type of send operation last performed on semaphore */ int send_type; /* ** Ownership nesting level for mutual exclusion semaphore. */ int recursion_level; /* ** Task control block ptr for task which currently owns semaphore */ vxwk2pthread_cb_t * current_owner; /* ** Pointer to next semaphore control block in semaphore list. */ struct vxwk_sema4 * nxt_sema4; /* ** First task control block in list of tasks waiting on semaphore */ vxwk2pthread_cb_t * first_susp;} vxwk_sema4_t;/******************************************************************************* External function and data references*****************************************************************************/extern void * ts_malloc( size_t blksize );extern void ts_free( void *blkaddr );extern vxwk2pthread_cb_t * my_tcb( void );extern void taskLock( void );extern void taskUnlock( void );extern STATUS taskDelay( int interval );extern STATUS taskSafe( void );extern STATUS taskUnsafe( void );extern void link_susp_tcb( vxwk2pthread_cb_t **list_head, vxwk2pthread_cb_t *new_entry );extern void unlink_susp_tcb( vxwk2pthread_cb_t **list_head, vxwk2pthread_cb_t *entry );extern int signal_for_my_task( vxwk2pthread_cb_t **list_head, int pend_order );/******************************************************************************* VxWorks-to-pthread Global Data Structures*****************************************************************************//*** sema4_list is a linked list of semaphore control blocks. It is used to** validate semaphores by their ID numbers.*/static vxwk_sema4_t * sema4_list;/*** sema4_list_lock is a mutex used to serialize access to the semaphore list*/static pthread_mutex_t sema4_list_lock = PTHREAD_MUTEX_INITIALIZER;/******************************************************************************* sema4_valid - verifies whether the specified semaphore still exists, and if** so, locks exclusive access to the semaphore for the caller.*****************************************************************************/static int sema4_valid( vxwk_sema4_t *sema4 ){ vxwk_sema4_t *current_smcb; int found_sema4; found_sema4 = FALSE; /* ** Protect the semaphore list while we examine and modify it. */ pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock, (void *)&sema4_list_lock ); pthread_mutex_lock( &sema4_list_lock ); if ( sema4_list != (vxwk_sema4_t *)NULL ) { /* ** One or more semaphores already exist in the semaphore list... ** Scan the existing semaphores for a matching ID. */ for ( current_smcb = sema4_list; current_smcb != (vxwk_sema4_t *)NULL; current_smcb = current_smcb->nxt_sema4 ) { if ( current_smcb == sema4 ) { /* ** Lock mutex for semaphore access (it is assumed that a ** 'pthread_cleanup_push()' has already been performed ** by the caller in case of unexpected thread termination.) */ pthread_mutex_lock( &(sema4->sema4_lock) ); found_sema4 = TRUE; break; } } } /* ** Re-enable access to the semaphore list by other threads. */ pthread_mutex_unlock( &sema4_list_lock ); pthread_cleanup_pop( 0 ); return( found_sema4 );}/******************************************************************************* link_smcb - appends a new semaphore control block pointer to the sema4_list*****************************************************************************/static void link_smcb( vxwk_sema4_t *new_sema4 ){ vxwk_sema4_t *current_smcb; /* ** Protect the semaphore list while we examine and modify it. */ pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock, (void *)&sema4_list_lock ); pthread_mutex_lock( &sema4_list_lock ); new_sema4->nxt_sema4 = (vxwk_sema4_t *)NULL; if ( sema4_list != (vxwk_sema4_t *)NULL ) { /* ** One or more semaphores already exist in the semaphore list... ** Insert the new entry at the tail of the list. */ for ( current_smcb = sema4_list; current_smcb->nxt_sema4 != (vxwk_sema4_t *)NULL; current_smcb = current_smcb->nxt_sema4 ); current_smcb->nxt_sema4 = new_sema4;#ifdef DIAG_PRINTFS printf( "\r\nadd semaphore cb @ %p to list @ %p", new_sema4, current_smcb );#endif } else { /* ** this is the first semaphore being added to the semaphore list. */ sema4_list = new_sema4;#ifdef DIAG_PRINTFS printf( "\r\nadd semaphore cb @ %p to list @ %p", new_sema4, &sema4_list );#endif } /* ** Re-enable access to the semaphore list by other threads. */ pthread_mutex_unlock( &sema4_list_lock ); pthread_cleanup_pop( 0 );}/******************************************************************************* unlink_smcb - removes a semaphore control block pointer from the sema4_list*****************************************************************************/static vxwk_sema4_t * unlink_smcb( vxwk_sema4_t *smid ){ vxwk_sema4_t *current_smcb; vxwk_sema4_t *selected_smcb; selected_smcb = (vxwk_sema4_t *)NULL; if ( sema4_list != (vxwk_sema4_t *)NULL ) { /* ** One or more semaphores exist in the semaphore list... ** Protect the semaphore list while we examine and modify it. */ pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock, (void *)&sema4_list_lock ); pthread_mutex_lock( &sema4_list_lock ); /* ** Scan the semaphore list for an smcb with a matching semaphore ID */ if ( sema4_list == smid ) { /* ** The first semaphore in the list matches the selected ID */ selected_smcb = sema4_list; sema4_list = selected_smcb->nxt_sema4;#ifdef DIAG_PRINTFS printf( "\r\ndel semaphore cb @ %p from list @ %p", selected_smcb, &sema4_list );#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 != (vxwk_sema4_t *)NULL; current_smcb = current_smcb->nxt_sema4 ) { if ( current_smcb->nxt_sema4 == 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 );}/******************************************************************************* new_sema4 - creates a new VxWorks semaphore using pthreads resources*****************************************************************************/vxwk_sema4_t * new_sema4( int count ){ vxwk_sema4_t *semaphore; /* ** First allocate memory for the semaphore control block */ semaphore = (vxwk_sema4_t *)ts_malloc( sizeof( vxwk_sema4_t ) ); if ( semaphore != (vxwk_sema4_t *)NULL ) { /* ** Ok... got a control block. ** Initialize the token count. */ semaphore->token_count = count; /* ** 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 ); /* ** Type of send operation last performed on semaphore */ semaphore->send_type = SEND; /* ** Ownership nesting level for mutual exclusion semaphore. */ semaphore->recursion_level = 0; /* ** Task control block ptr for task which currently owns semaphore */ semaphore->current_owner = (vxwk2pthread_cb_t *)NULL; /* ** First task control block in list of tasks waiting on semaphore */ semaphore->first_susp = (vxwk2pthread_cb_t *)NULL; } return( semaphore );}/******************************************************************************* semBCreate - creates a VxWorks binary semaphore*****************************************************************************/vxwk_sema4_t * semBCreate( int opt, int initial_state ){ vxwk_sema4_t *semaphore; /* ** First allocate memory for the semaphore control block */ if ( initial_state == 0 ) semaphore = new_sema4( 0 ); else semaphore = new_sema4( 1 ); if ( semaphore != (vxwk_sema4_t *)NULL ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -