bionic semaphore学习

8 篇文章 0 订阅

文件位置:bionic/libc/bionic/semaphore.c

头文件位于bionic/libc/include/semaphore.h中

下面是头文件定义的接口:

__BEGIN_DECLS

#define  SEM_FAILED  NULL

extern int sem_init(sem_t *sem, int pshared, unsigned int value);

extern int    sem_close(sem_t *);
extern int    sem_destroy(sem_t *);
extern int    sem_getvalue(sem_t *, int *);
extern int    sem_init(sem_t *, int, unsigned int);
extern sem_t *sem_open(const char *, int, ...);
extern int    sem_post(sem_t *);
extern int    sem_trywait(sem_t *);
extern int    sem_unlink(const char *);
extern int    sem_wait(sem_t *);

struct timespec;
extern int    sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

__END_DECLS

#endif /* _SEMAPHORE_H */

0. 信号量sem_t

先看结构:

typedef struct {
    volatile unsigned int  count;
} sem_t;


32位无符号整形;

其中第一位表示shared flag

其他31位表示counter

下面的文字描述:

value值:

-1表示正在等待信号,抢夺资源中;

0或者大于0表示处于非等待状态;

-2表示运行时无效;

/* In this implementation, a semaphore contains a
 * 31-bit signed value and a 1-bit 'shared' flag
 * (for process-sharing purpose).
 *
 * We use the value -1 to indicate contention on the
 * semaphore, 0 or more to indicate uncontended state,
 * any value lower than -2 is invalid at runtime.
 *
 * State diagram:
 *
 * post(1)  ==> 2
 * post(0)  ==> 1
 * post(-1) ==> 1, then wake all waiters
 *
 * wait(2)  ==> 1
 * wait(1)  ==> 0
 * wait(0)  ==> -1 then wait for a wake up + loop
 * wait(-1) ==> -1 then wait for a wake up + loop
 *
 */

/* Use the upper 31-bits for the counter, and the lower one
 * for the shared flag.
 */




1. __sem_dec

将信号值原子减1,然后返回先前的旧值。

/* Decrement a semaphore's value atomically,
 * and return the old one. As a special case,
 * this returns immediately if the value is
 * negative (i.e. -1)
 */
static int
__sem_dec(volatile unsigned int *pvalue)
{
    unsigned int shared = (*pvalue & SEMCOUNT_SHARED_MASK);
    unsigned int old, new;
    int          ret;

    do {
        old = (*pvalue & SEMCOUNT_VALUE_MASK);
        ret = SEMCOUNT_TO_VALUE(old);
        if (ret < 0)
            break;

        new = SEMCOUNT_DECREMENT(old);
    }
    while (__bionic_cmpxchg((int)(old|shared),
                            (int)(new|shared),
                            (volatile int *)pvalue) != 0);
    return ret;
}

先将old去出来,然后右移一位,得到counter值,(因为第一位是flag);

若得到的ret < 0,那么跳出循环,返回;否则就减去1;


2. __sem_inc

原子加1,返回旧值

/* "Increment" the value of a semaphore atomically and
 * return its old value. Note that this implements
 * the special case of "incrementing" any negative
 * value to +1 directly.
 *
 * NOTE: The value will _not_ wrap above SEM_VALUE_MAX
 */
static int
__sem_inc(volatile unsigned int *pvalue)
{
    unsigned int  shared = (*pvalue & SEMCOUNT_SHARED_MASK);
    unsigned int  old, new;
    int           ret;

    do {
        old = (*pvalue & SEMCOUNT_VALUE_MASK);
        ret = SEMCOUNT_TO_VALUE(old);

        /* Can't go higher than SEM_MAX_VALUE */
        if (ret == SEM_MAX_VALUE)
            break;

        /* If the counter is negative, go directly to +1,
         * otherwise just increment */
        if (ret < 0)
            new = SEMCOUNT_ONE;
        else
            new = SEMCOUNT_INCREMENT(old);
    }
    while ( __bionic_cmpxchg((int)(old|shared),
                             (int)(new|shared),
                             (volatile int*)pvalue) != 0);

    return ret;
}

取出old,然后取出counter, 若ret达到最大值了,则返回,

若ret < 0 , 那么将new 设置为1;

否则,在old之上加1;

3. __sem_trydec

跟2相似,只是如果value已经小于或者等于0,那么返回old,不做任何其他事情;

/* Same as __sem_dec, but will not touch anything if the
 * value is already negative *or* 0. Returns the old value.
 */
static int
__sem_trydec(volatile unsigned int *pvalue)
{
    unsigned int shared = (*pvalue & SEMCOUNT_SHARED_MASK);
    unsigned int old, new;
    int          ret;

    do {
        old = (*pvalue & SEMCOUNT_VALUE_MASK);
        ret = SEMCOUNT_TO_VALUE(old);
        if (ret <= 0)
            break;

        new = SEMCOUNT_DECREMENT(old);
    }
    while (__bionic_cmpxchg((int)(old|shared),
                            (int)(new|shared),
                            (volatile int *)pvalue) != 0);

    return ret;
}

与2不同点似乎就在于,如果ret == 0了,它也立即返回了。并不做-1操作;



4. sem_timedwait

计时等待,调用了__futex_wait_ex

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)
{
    int  ret;
    unsigned int shared;

    if (sem == NULL) {
        errno = EINVAL;
        return -1;
    }

    /* POSIX says we need to try to decrement the semaphore
     * before checking the timeout value. Note that if the
     * value is currently 0, __sem_trydec() does nothing.
     */
    if (__sem_trydec(&sem->count) > 0) {
        ANDROID_MEMBAR_FULL();
        return 0;
    }

    /* Check it as per Posix */
    if (abs_timeout == NULL    ||
        abs_timeout->tv_sec < 0 ||
        abs_timeout->tv_nsec < 0 ||
        abs_timeout->tv_nsec >= 1000000000)
    {
        errno = EINVAL;
        return -1;
    }

    shared = SEM_GET_SHARED(sem);

    for (;;) {
        struct timespec ts;
        int             ret;

        /* Posix mandates CLOCK_REALTIME here */
        clock_gettime( CLOCK_REALTIME, &ts );
        ts.tv_sec  = abs_timeout->tv_sec - ts.tv_sec;
        ts.tv_nsec = abs_timeout->tv_nsec - ts.tv_nsec;
        if (ts.tv_nsec < 0) {
            ts.tv_nsec += 1000000000;
            ts.tv_sec  -= 1;
        }

        if (ts.tv_sec < 0 || ts.tv_nsec < 0) {
            errno = ETIMEDOUT;
            return -1;
        }

        /* Try to grab the semaphore. If the value was 0, this
         * will also change it to -1 */
        if (__sem_dec(&sem->count) > 0) { //如果是0,那么这个操作可能将其变为-1,不过先减去1
            ANDROID_MEMBAR_FULL();
            break;
        }

        /* Contention detected. wait for a wakeup event */
        ret = __futex_wait_ex(&sem->count, shared, shared|SEMCOUNT_MINUS_ONE, &ts);

        /* return in case of timeout or interrupt */
        if (ret == -ETIMEDOUT || ret == -EINTR) {
            errno = -ret;
            return -1;
        }
    }
    return 0;
}


5. sem_wait

等待,先减去1,然后wait事件唤醒,__futex_wait_ex;

/* lock a semaphore */
int sem_wait(sem_t *sem)
{
    unsigned shared;

    if (sem == NULL) {
        errno = EINVAL;
        return -1;
    }

    shared = SEM_GET_SHARED(sem);

    for (;;) {
        if (__sem_dec(&sem->count) > 0)
            break;

        __futex_wait_ex(&sem->count, shared, shared|SEMCOUNT_MINUS_ONE, NULL);
    }
    ANDROID_MEMBAR_FULL();
    return 0;
}


6. sem_post

先将信号值+1,然后发送信号,唤醒;切记这次序


/* Unlock a semaphore */
int sem_post(sem_t *sem)
{
    unsigned int shared;
    int          old;

    if (sem == NULL)
        return EINVAL;

    shared = SEM_GET_SHARED(sem);

    ANDROID_MEMBAR_FULL();
    old = __sem_inc(&sem->count); //加1
    if (old < 0) {
        /* contention on the semaphore, wake up all waiters */
        __futex_wake_ex(&sem->count, shared, INT_MAX); //唤醒
    }
    else if (old == SEM_MAX_VALUE) {
        /* overflow detected */
        errno = EOVERFLOW;
        return -1;
    }

    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值