class Semaphore

Defined at line 33 of file ../../zircon/kernel/include/kernel/semaphore.h

A basic counting semaphore used to control access to a shared resource.

Think of Semaphore as a gatekeeper that allows a certain number of threads to

pass through a gate so they can access some resource.

Threads queue up at the gate by calling Wait and then block until the

gatekeeper lets them through or they give up and leave the queue because of

timeout or thread signal. In the case of timeout or thread signal, the

waiter may not proceed to the resource.

Calling Post tells the gatekeeper that they may immediately admit one through

the gate (if there's a waiter in the queue) or admit one in the future once a

waiter has queued up.

Public Methods

void Post (OwnedWaitQueue * queue_to_own)

Every call to this method must wake one waiter unless the queue is empty.

When leaving this method, we must have either

- incremented a non-negative count or

- unblocked one thread and

- left an empty queue with a count of zero or

- left a non-empty queue with negative count

Defined at line 25 of file ../../zircon/kernel/kernel/semaphore.cc

void Semaphore (int64_t initial_count)

Defined at line 35 of file ../../zircon/kernel/include/kernel/semaphore.h

void Semaphore (const Semaphore & )

Defined at line 37 of file ../../zircon/kernel/include/kernel/semaphore.h

void Semaphore (Semaphore && )

Defined at line 38 of file ../../zircon/kernel/include/kernel/semaphore.h

Semaphore & operator= (const Semaphore & )

Defined at line 39 of file ../../zircon/kernel/include/kernel/semaphore.h

void ~Semaphore ()

Defined at line 40 of file ../../zircon/kernel/include/kernel/semaphore.h

int64_t count ()

Observe the current internal count of the semaphore.

This should only be used for testing/diagnostic purposes.

Defined at line 67 of file ../../zircon/kernel/include/kernel/semaphore.h

uint64_t num_waiters ()

Observe the current internal count of waiters.

This should only be used for testing/diagnostic purposes.

Defined at line 72 of file ../../zircon/kernel/include/kernel/semaphore.h

zx_status_t Wait (const Deadline & deadline)

Handling failed waits -- Waits can fail due to timeout or thread signal.

When a Wait fails, the caller cannot proceed to the resource guarded by the

semaphore. It's as if the waiter gave up and left. We want to ensure failed

waits do not impact other waiters. While it seems like a failed wait should

simply "undo" its decrement, it is not safe to do so in Wait. Instead, we

"fix" the count in subsequent call to Post.

To understand why we can't simply fix the count in Wait after returning from

Block, let's look at an alternative (buggy) implementation of Post and Wait.

In this hypothetical implementation, Post increments and Wait decrements

before Block, but also increments if Block returns an error. With this

hypothetical implementation in mind, consider the following sequence of

operations:

Q C

0 0

1W 1 -1 B

1T 0 -1

2P 0 0

3W 1 -1 B

1R 1 0

The way to read the sequence above is that the wait queue (Q) starts empty

and the count (C) starts at zero. Thread1 calls Wait (1W) and blocks (B).

Thread1's times out (1T) and is removed from the queue, but has not yet

resumed execution. Thread2 calls Post (2P), but does not unblock any threads

because it finds an empty queue. Thread3 calls Wait (3W) and blocks (B).

Thread1 returns from Block, resumes execution (1R), and increments the count.

At this point Thread3 is blocked as it should be (two Posts and one failed

Wait), however, a subsequent call to Post will not unblock it. We have a

"lost wakeup".

Defined at line 183 of file ../../zircon/kernel/kernel/semaphore.cc