1// vi:set ft=cpp: -*- Mode: C++ -*-
2/**
3 * \file
4 * Semaphore class definition.
5 */
6/*
7 * (c) 2015 Alexander Warg <alexander.warg@kernkonzept.com>
8 *
9 * This file is part of TUD:OS and distributed under the terms of the
10 * GNU General Public License 2.
11 * Please see the COPYING-GPL-2 file for details.
12 *
13 * As a special exception, you may use this file as part of a free software
14 * library without restriction.  Specifically, if other files instantiate
15 * templates or use macros or inline functions from this file, or you compile
16 * this file and link it with other files to produce an executable, this
17 * file does not by itself cause the resulting executable to be covered by
18 * the GNU General Public License.  This exception does not however
19 * invalidate any other reasons why the executable file might be covered by
20 * the GNU General Public License.
21 */
22
23#pragma once
24
25#include <l4/sys/irq>
26#include <l4/sys/semaphore.h>
27
28namespace L4 {
29
30/**
31 * Kernel-provided semaphore object.
32 *
33 * This is the interface for kernel-provided semaphore objects. The
34 * object provides the classical functions `up()` and `down()` for
35 * counting the semaphore and blocking.  The semaphore is a
36 * Triggerable with respect to the `up()` function, this means that a
37 * semaphore can be bound to an interrupt line at an ICU (L4::Icu) and
38 * incoming interrupts increment the semaphore counter.
39 *
40 * The `down()` method decrements the semaphore counter and blocks
41 * if the counter is already zero.  Blocking on a semaphore may---as all
42 * blocking operations---either return successfully, or be aborted due to
43 * an expired timeout provided to the `down()` operation, or due to an
44 * L4::Thread::ex_regs() operation with the #L4_THREAD_EX_REGS_CANCEL
45 * flag set.
46 *
47 * The main reason for using a semaphore instead of an L4::Irq is to ensure
48 * that incoming trigger signals do not interfere with any open-wait
49 * operations, as used for example in a server loop.
50 */
51struct Semaphore : Kobject_t<Semaphore, Triggerable, L4_PROTO_SEMAPHORE>
52{
53  /**
54   * Semaphore up operation (wrapper for trigger()).
55   *
56   * \utcb{utcb}
57   *
58   * \return Send-only IPC message return tag. Use l4_ipc_error() to check for
59   *         errors, do **not** use l4_error().
60   *
61   * Increases the semaphore counter by one if it is smaller than an
62   * unspecified limit. The unspecified limit is guaranteed to be at
63   * least 2^31-1.
64   */
65  l4_msgtag_t up(l4_utcb_t *utcb = l4_utcb()) noexcept
66  { return trigger(utcb); }
67
68  /**
69   * Semaphore down operation.
70   *
71   * \param timeout  Timeout for blocking the semaphore down operation.
72   *                 Note: The receive timeout of this timeout-pair is
73   *                 significant for blocking, the send part is usually
74   *                 non-blocking.
75   * \utcb{utcb}
76   *
77   * \return IPC message return tag. Use l4_ipc_error() to check for
78   *         a timeout or a cancel condition.
79   *
80   * This method decrements the semaphore counter by one, or blocks if the
81   * counter is already zero, until either a timeout or cancel condition hits
82   * or the counter is increased by an `up()` operation.
83   */
84  l4_msgtag_t down(l4_timeout_t timeout = L4_IPC_NEVER,
85                   l4_utcb_t *utcb = l4_utcb()) noexcept
86  { return l4_semaphore_down_u(cap(), timeout, utcb);  }
87};
88
89}
90