1// vi:set ft=cpp: -*- Mode: C++ -*-
2/**
3 * \file
4 * \brief   Error helper.
5 */
6/*
7 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
8 *               Alexander Warg <warg@os.inf.tu-dresden.de>,
9 *               Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
10 *     economic rights: Technische Universität Dresden (Germany)
11 *
12 * This file is part of TUD:OS and distributed under the terms of the
13 * GNU General Public License 2.
14 * Please see the COPYING-GPL-2 file for details.
15 *
16 * As a special exception, you may use this file as part of a free software
17 * library without restriction.  Specifically, if other files instantiate
18 * templates or use macros or inline functions from this file, or you compile
19 * this file and link it with other files to produce an executable, this
20 * file does not by itself cause the resulting executable to be covered by
21 * the GNU General Public License.  This exception does not however
22 * invalidate any other reasons why the executable file might be covered by
23 * the GNU General Public License.
24 */
25#pragma once
26
27#include <l4/sys/types.h>
28#include <l4/cxx/exceptions>
29#include <l4/cxx/type_traits>
30#include <l4/sys/err.h>
31
32namespace L4Re {
33
34#ifdef __EXCEPTIONS
35
36/**
37 * \brief Generate C++ exception
38 *
39 * \param err   Error value
40 * \param extra Optional text for exception (default "")
41 *
42 * This function throws an L4 exception. The exact exception type depends on
43 * the error value (err). This function does never return.
44 */
45[[noreturn]] inline void throw_error(long err, char const *extra = "")
46{
47  switch (err)
48    {
49    case -L4_ENOENT: throw (L4::Element_not_found(extra));
50    case -L4_ENOMEM: throw (L4::Out_of_memory(extra));
51    case -L4_EEXIST: throw (L4::Element_already_exists(extra));
52    case -L4_ERANGE: throw (L4::Bounds_error(extra));
53    default: throw (L4::Runtime_error(err, extra));
54    }
55}
56
57/**
58 * \brief Generate C++ exception on error
59 *
60 * \param err   Error value, if negative exception will be thrown
61 * \param extra Optional text for exception (default "")
62 * \param ret   Optional value for exception, default is error value (err)
63 *
64 * This function throws an exception if the err is negative and
65 * otherwise returns err.
66 */
67inline
68long chksys(long err, char const *extra = "", long ret = 0)
69{
70  if (L4_UNLIKELY(err < 0))
71    throw_error(ret ? ret : err, extra);
72
73  return err;
74}
75
76/**
77 * \brief Generate C++ exception on error
78 *
79 * \param t     Message tag.
80 * \param extra Optional text for exception (default "")
81 * \param utcb  Option UTCB
82 * \param ret   Optional value for exception, default is error value (err)
83 *
84 * This function throws an exception if the message tag contains an error or
85 * the label in the message tag is negative. Otherwise the label in the
86 * message tag is returned.
87 */
88inline
89long chksys(l4_msgtag_t const &t, char const *extra = "",
90            l4_utcb_t *utcb = l4_utcb(), long ret = 0)
91{
92  if (L4_UNLIKELY(t.has_error()))
93    throw_error(ret ? ret : l4_error_u(t, utcb), extra);
94  else if (L4_UNLIKELY(t.label() < 0))
95    throw_error(ret ? ret: t.label(), extra);
96
97  return t.label();
98}
99
100/**
101 * \brief Generate C++ exception on error
102 *
103 * \param t     Message tag.
104 * \param utcb  UTCB.
105 * \param extra Optional text for exception (default "")
106 *
107 * This function throws an exception if the message tag contains an error or
108 * the label in the message tag is negative. Otherwise the label in the
109 * message tag is returned.
110 */
111inline
112long chksys(l4_msgtag_t const &t, l4_utcb_t *utcb, char const *extra = "")
113{ return chksys(t, extra, utcb); }
114
115#if 0
116inline
117long chksys(long ret, long err, char const *extra = "")
118{
119  if (L4_UNLIKELY(ret < 0))
120    throw_error(err, extra);
121
122  return ret;
123}
124#endif
125
126/**
127 * Check for valid capability or raise C++ exception
128 *
129 * \tparam T  Type of object to check, must be capability-like
130 *            (L4::Cap, L4Re::Util::Unique_cap etc.)
131 *
132 * \param cap    Capability value to check.
133 * \param extra  Optional text for exception.
134 * \param err    Error value for exception or 0 if the capability value
135 *               should be used.
136 *
137 * This function checks whether the capability is valid. If the capability
138 * is invalid an C++ exception is generated, using err if err is not zero,
139 * otherwise the capability value is used. A valid capability will just be
140 * returned.
141 */
142template<typename T>
143inline
144#if __cplusplus >= 201103L
145T chkcap(T &&cap, char const *extra = "", long err = -L4_ENOMEM)
146#else
147T chkcap(T cap, char const *extra = "", long err = -L4_ENOMEM)
148#endif
149{
150  if (L4_UNLIKELY(!cap.is_valid()))
151    throw_error(err ? err : cap.cap(), extra);
152
153#if __cplusplus >= 201103L
154  return cxx::forward<T>(cap);
155#else
156  return cap;
157#endif
158}
159
160/**
161 * Test a message tag for IPC errors.
162 *
163 * \param tag    Message tag returned by the IPC.
164 * \param extra  Exception message in case of error.
165 * \param utcb   The UTCB used in the IPC operation.
166 *
167 * \returns  On IPC error an exception is thrown, otherwise `tag` is returned.
168 * \throws L4::Runtime_exception with the translated IPC error code
169 *
170 * This function does not check the message tag's label value.
171 *
172 * \note This must be called on a message tag before the UTCB is changed.
173 */
174inline
175l4_msgtag_t
176chkipc(l4_msgtag_t tag, char const *extra = "",
177       l4_utcb_t *utcb = l4_utcb())
178{
179  if (L4_UNLIKELY(tag.has_error()))
180    chksys(l4_error_u(tag, utcb), extra);
181
182  return tag;
183}
184#endif
185
186}
187