1// vi:set ft=cpp: -*- Mode: C++ -*-
2/*
3 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
4 *               Alexander Warg <warg@os.inf.tu-dresden.de>
5 *     economic rights: Technische Universität Dresden (Germany)
6 *
7 * This file is part of TUD:OS and distributed under the terms of the
8 * GNU General Public License 2.
9 * Please see the COPYING-GPL-2 file for details.
10 *
11 * As a special exception, you may use this file as part of a free software
12 * library without restriction.  Specifically, if other files instantiate
13 * templates or use macros or inline functions from this file, or you compile
14 * this file and link it with other files to produce an executable, this
15 * file does not by itself cause the resulting executable to be covered by
16 * the GNU General Public License.  This exception does not however
17 * invalidate any other reasons why the executable file might be covered by
18 * the GNU General Public License.
19 */
20
21#pragma once
22
23#include <l4/re/event>
24#include <l4/re/event-sys.h>
25#include <l4/re/rm>
26
27#include <cstring>
28
29namespace L4Re { namespace Util {
30
31/**
32 * \brief Event_buffer utility class.
33 * \ingroup api_l4re_util
34 */
35template< typename PAYLOAD >
36class Event_buffer_t : public L4Re::Event_buffer_t<PAYLOAD>
37{
38private:
39  void *_buf;
40public:
41  /**
42   * \brief Return the buffer.
43   *
44   * \return Pointer to the event buffer.
45   */
46  void *buf() const noexcept { return _buf; }
47
48  /**
49   * \brief Attach event buffer from address space.
50   *
51   * \param ds   Dataspace of the event buffer.
52   * \param rm   Region manager to attach buffer to.
53   *
54   * \return 0 on success, negative error code otherwise.
55   */
56  long attach(L4::Cap<L4Re::Dataspace> ds, L4::Cap<L4Re::Rm> rm) noexcept
57  {
58    l4_addr_t sz = ds->size();
59    _buf = 0;
60
61    long r = rm->attach(&_buf, sz,
62                        L4Re::Rm::F::Search_addr | L4Re::Rm::F::RW,
63                        L4::Ipc::make_cap_rw(ds));
64    if (r < 0)
65      return r;
66
67    *(L4Re::Event_buffer_t<PAYLOAD>*)this = L4Re::Event_buffer_t<PAYLOAD>(_buf, sz);
68    return 0;
69  }
70
71  /**
72   * \brief Detach event buffer from address space.
73   *
74   * \param rm   Region manager to detach buffer from.
75   *
76   * \return 0 on success, negative error code otherwise.
77   */
78  long detach(L4::Cap<L4Re::Rm> rm) noexcept
79  {
80    L4::Cap<L4Re::Dataspace> ds;
81    if (_buf)
82      return rm->detach(_buf, &ds);
83    return 0;
84  }
85
86};
87
88/**
89 * \brief An event buffer consumer.
90 * \ingroup api_l4re_util
91 */
92template< typename PAYLOAD >
93class Event_buffer_consumer_t : public Event_buffer_t<PAYLOAD>
94{
95public:
96
97  /**
98   * \brief Call function on every available event.
99   *
100   * \param cb    Function callback.
101   * \param data  Data to pass as an argument to the callback.
102   */
103  template< typename CB, typename D >
104  void foreach_available_event(CB const &cb, D data = D())
105  {
106    typename Event_buffer_t<PAYLOAD>::Event *e;
107    while ((e = Event_buffer_t<PAYLOAD>::next()))
108      {
109        cb(e, data);
110        e->free();
111      }
112  }
113
114  /**
115   * \brief Continuously wait for events and process them.
116   *
117   * \param irq     Event signal to wait for.
118   * \param thread  Thread capability of the thread calling this function.
119   * \param cb      Callback function that is called for each received event.
120   * \param data    Data to pass as an argument to the processing callback.
121   *
122   * \note This function never returns.
123   */
124  template< typename CB, typename D >
125  void process(L4::Cap<L4::Irq> irq,
126               L4::Cap<L4::Thread> thread,
127               CB const &cb, D data = D())
128  {
129
130    if (l4_error(irq->bind_thread(thread, 0)))
131      return;
132
133    while (1)
134      {
135        long r;
136        r = l4_ipc_error(l4_irq_receive(irq.cap(), L4_IPC_NEVER),
137                         l4_utcb());
138        if (r)
139          continue;
140
141        foreach_available_event(cb, data);
142      }
143  }
144};
145
146typedef Event_buffer_t<Default_event_payload> Event_buffer;
147typedef Event_buffer_consumer_t<Default_event_payload> Event_buffer_consumer;
148
149}}
150