函数源码

Linux Kernel

v5.5.9

Brick Technologies Co., Ltd

Source File:ipc\sem.c Create Date:2022-07-27 18:18:59
首页 Copyright©Brick

607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
/**
 * perform_atomic_semop[_slow] - Attempt to perform semaphore
 *                               operations on a given array.
 * @sma: semaphore array
 * @q: struct sem_queue that describes the operation
 *
 * Caller blocking are as follows, based the value
 * indicated by the semaphore operation (sem_op):
 *
 *  (1) >0 never blocks.
 *  (2)  0 (wait-for-zero operation): semval is non-zero.
 *  (3) <0 attempting to decrement semval to a value smaller than zero.
 *
 * Returns 0 if the operation was possible.
 * Returns 1 if the operation is impossible, the caller must sleep.
 * Returns <0 for error codes.
 */
static int perform_atomic_semop_slow(struct sem_array *sma, struct sem_queue *q)
{
    int result, sem_op, nsops;
    struct pid *pid;
    struct sembuf *sop;
    struct sem *curr;
    struct sembuf *sops;
    struct sem_undo *un;
 
    sops = q->sops;
    nsops = q->nsops;
    un = q->undo;
 
    for (sop = sops; sop < sops + nsops; sop++) {
        int idx = array_index_nospec(sop->sem_num, sma->sem_nsems);
        curr = &sma->sems[idx];
        sem_op = sop->sem_op;
        result = curr->semval;
 
        if (!sem_op && result)
            goto would_block;
 
        result += sem_op;
        if (result < 0)
            goto would_block;
        if (result > SEMVMX)
            goto out_of_range;
 
        if (sop->sem_flg & SEM_UNDO) {
            int undo = un->semadj[sop->sem_num] - sem_op;
            /* Exceeding the undo range is an error. */
            if (undo < (-SEMAEM - 1) || undo > SEMAEM)
                goto out_of_range;
            un->semadj[sop->sem_num] = undo;
        }
 
        curr->semval = result;
    }
 
    sop--;
    pid = q->pid;
    while (sop >= sops) {
        ipc_update_pid(&sma->sems[sop->sem_num].sempid, pid);
        sop--;
    }
 
    return 0;
 
out_of_range:
    result = -ERANGE;
    goto undo;
 
would_block:
    q->blocking = sop;
 
    if (sop->sem_flg & IPC_NOWAIT)
        result = -EAGAIN;
    else
        result = 1;
 
undo:
    sop--;
    while (sop >= sops) {
        sem_op = sop->sem_op;
        sma->sems[sop->sem_num].semval -= sem_op;
        if (sop->sem_flg & SEM_UNDO)
            un->semadj[sop->sem_num] += sem_op;
        sop--;
    }
 
    return result;
}