1 /*
2 * \brief CPU (processing time) manager session interface
3 * \author Christian Helmuth
4 * \date 2006-06-27
5 *
6 * :Question:
7 *
8 * Why are thread operations not methods of the thread but
9 * methods of the CPU session?
10 *
11 * :Answer:
12 *
13 * This enables the CPU session to impose policies on thread
14 * operations. These policies are based on the session
15 * construction arguments. If thread operations would be
16 * provided as thread methods, Thread would need to consult
17 * its container object (its CPU session) about the authorization
18 * of each operation and, thereby, would introduce a circular
19 * dependency between CPU session and Thread.
20 */
21
22 /*
23 * Copyright (C) 2006-2013 Genode Labs GmbH
24 *
25 * This file is part of the Genode OS framework, which is distributed
26 * under the terms of the GNU General Public License version 2.
27 */
28
29 #ifndef _INCLUDE__CPU_SESSION__CPU_SESSION_H_
30 #define _INCLUDE__CPU_SESSION__CPU_SESSION_H_
31
32 #include <base/stdint.h>
33 #include <base/exception.h>
34 #include <base/thread_state.h>
35 #include <base/rpc_args.h>
36 #include <base/signal.h>
37 #include <base/affinity.h>
38 #include <thread/capability.h>
39 #include <pager/capability.h>
40 #include <session/session.h>
41 #include <ram_session/ram_session.h>
42
43 namespace Genode {
44
45 struct Cpu_session : Session
46 {
47 /*********************
48 ** Exception types **
49 *********************/
50
51 class Thread_creation_failed : public Exception { };
52 class State_access_failed : public Exception { };
53 class Out_of_metadata : public Exception { };
54
55 static const char *service_name() { return "CPU"; }
56
57 enum { THREAD_NAME_LEN = 48 };
58 enum { PRIORITY_LIMIT = 1 << 16 };
59 enum { DEFAULT_PRIORITY = 0 };
60
61 typedef Rpc_in_buffer<THREAD_NAME_LEN> Name;
62
63 virtual ~Cpu_session() { }
64
65 /**
66 * Create a new thread
67 *
68 * \param name name for the thread
69 * \param utcb Base of the UTCB that will be used by the thread
70 * \return capability representing the new thread
71 * \throw Thread_creation_failed
72 * \throw Out_of_metadata
73 */
74 virtual Thread_capability create_thread(Name const &name,
75 addr_t utcb = 0) = 0;
76
77 /**
78 * Get dataspace of the UTCB that is used by the specified thread
79 */
80 virtual Ram_dataspace_capability utcb(Thread_capability thread) = 0;
81
82 /**
83 * Kill an existing thread
84 *
85 * \param thread capability of the thread to kill
86 */
87 virtual void kill_thread(Thread_capability thread) = 0;
88
89 /**
90 * Set paging capabilities for thread
91 *
92 * \param thread thread to configure
93 * \param pager capability used to propagate page faults
94 */
95 virtual int set_pager(Thread_capability thread,
96 Pager_capability pager) = 0;
97
98 /**
99 * Modify instruction and stack pointer of thread - start the
100 * thread
101 *
102 * \param thread thread to start
103 * \param ip initial instruction pointer
104 * \param sp initial stack pointer
105 *
106 * \return 0 on success
107 */
108 virtual int start(Thread_capability thread, addr_t ip, addr_t sp) = 0;
109
110 /**
111 * Pause the specified thread
112 *
113 * After calling this function, the execution of the thread can be
114 * continued by calling `resume`.
115 */
116 virtual void pause(Thread_capability thread) = 0;
117
118 /**
119 * Resume the specified thread
120 */
121 virtual void resume(Thread_capability thread) = 0;
122
123 /**
124 * Cancel a currently blocking operation
125 *
126 * \param thread thread to unblock
127 */
128 virtual void cancel_blocking(Thread_capability thread) = 0;
129
130 /**
131 * Get the current state of a specific thread
132 *
133 * \param thread targeted thread
134 * \return state of the targeted thread
135 * \throw State_access_failed
136 */
137 virtual Thread_state state(Thread_capability thread) = 0;
138
139 /**
140 * Override the current state of a specific thread
141 *
142 * \param thread targeted thread
143 * \param state state that shall be applied
144 * \throw State_access_failed
145 */
146 virtual void state(Thread_capability thread,
147 Thread_state const &state) = 0;
148
149 /**
150 * Register signal handler for exceptions of the specified thread
151 *
152 * If `thread` is an invalid capability, the default exception
153 * handler for the CPU session is set. This handler is used for
154 * all threads that have no explicitly installed exception handler.
155 * The new default signal handler will take effect for threads
156 * created after the call.
157 *
158 * On Linux, this exception is delivered when the process triggers
159 * a SIGCHLD. On other platforms, this exception is delivered on
160 * the occurrence of CPU exceptions such as division by zero.
161 */
162 virtual void exception_handler(Thread_capability thread,
163 Signal_context_capability handler) = 0;
164
165 /**
166 * Enable/disable single stepping for specified thread.
167 *
168 * Since this functions is currently supported by a small number of
169 * platforms, we provide a default implementation
170 *
171 * \param thread thread to set into single step mode
172 * \param enable true = enable single-step mode; false = disable
173 */
174 virtual void single_step(Thread_capability, bool) {}
175
176 /**
177 * Return affinity space of CPU nodes available to the CPU session
178 *
179 * The dimension of the affinity space as returned by this function
180 * represent the physical CPUs that are available.
181 */
182 virtual Affinity::Space affinity_space() const = 0;
183
184 /**
185 * Define affinity of thread to one or multiple CPU nodes
186 *
187 * In the normal case, a thread is assigned to a single CPU.
188 * Specifying more than one CPU node is supposed to principally
189 * allow a CPU service to balance the load of threads among
190 * multiple CPUs.
191 */
192 virtual void affinity(Thread_capability thread,
193 Affinity::Location affinity) = 0;
194
195 /**
196 * Translate generic priority value to kernel-specific priority levels
197 *
198 * \param pf_prio_limit maximum priority used for the kernel, must
199 * be power of 2
200 * \param prio generic priority value as used by the CPU
201 * session interface
202 * \param inverse order of platform priorities, if true
203 * `pf_prio_limit` corresponds to the highest
204 * priority, otherwise it refers to the
205 * lowest priority.
206 * \return platform-specific priority value
207 */
208 static unsigned scale_priority(unsigned pf_prio_limit, unsigned prio,
209 bool inverse = true)
210 {
211 /*
212 * Generic priority values are (0 is highest, `PRIORITY_LIMIT`
213 * is lowest. On platforms where priority levels are defined
214 * the other way round, we have to invert the priority value.
215 */
216 prio = inverse ? Cpu_session::PRIORITY_LIMIT - prio : prio;
217
218 /* scale value to platform priority range 0..pf_prio_limit */
219 return (prio*pf_prio_limit)/Cpu_session::PRIORITY_LIMIT;
220 }
221
222 /**
223 * Request trace control dataspace
224 *
225 * The trace-control dataspace is used to propagate tracing
226 * control information from core to the threads of a CPU session.
227 *
228 * The trace-control dataspace is accounted to the CPU session.
229 */
230 virtual Dataspace_capability trace_control() = 0;
231
232 /**
233 * Request index of a trace control block for given thread
234 *
235 * The trace control dataspace contains the control blocks for
236 * all threads of the CPU session. Each thread gets assigned a
237 * different index by the CPU service.
238 */
239 virtual unsigned trace_control_index(Thread_capability thread) = 0;
240
241 /**
242 * Request trace buffer for the specified thread
243 *
244 * The trace buffer is not accounted to the CPU session. It is
245 * owned by a TRACE session.
246 */
247 virtual Dataspace_capability trace_buffer(Thread_capability thread) = 0;
248
249 /**
250 * Request trace policy
251 *
252 * The trace policy buffer is not accounted to the CPU session. It
253 * is owned by a TRACE session.
254 */
255 virtual Dataspace_capability trace_policy(Thread_capability thread) = 0;
256
257
258 /*********************
259 ** RPC declaration **
260 *********************/
261
262 GENODE_RPC_THROW(Rpc_create_thread, Thread_capability, create_thread,
263 GENODE_TYPE_LIST(Thread_creation_failed, Out_of_metadata),
264 Name const &, addr_t);
265 GENODE_RPC(Rpc_utcb, Ram_dataspace_capability, utcb, Thread_capability);
266 GENODE_RPC(Rpc_kill_thread, void, kill_thread, Thread_capability);
267 GENODE_RPC(Rpc_set_pager, int, set_pager, Thread_capability, Pager_capability);
268 GENODE_RPC(Rpc_start, int, start, Thread_capability, addr_t, addr_t);
269 GENODE_RPC(Rpc_pause, void, pause, Thread_capability);
270 GENODE_RPC(Rpc_resume, void, resume, Thread_capability);
271 GENODE_RPC(Rpc_cancel_blocking, void, cancel_blocking, Thread_capability);
272 GENODE_RPC_THROW(Rpc_get_state, Thread_state, state,
273 GENODE_TYPE_LIST(State_access_failed),
274 Thread_capability);
275 GENODE_RPC_THROW(Rpc_set_state, void, state,
276 GENODE_TYPE_LIST(State_access_failed),
277 Thread_capability, Thread_state const &);
278 GENODE_RPC(Rpc_exception_handler, void, exception_handler,
279 Thread_capability, Signal_context_capability);
280 GENODE_RPC(Rpc_single_step, void, single_step, Thread_capability, bool);
281 GENODE_RPC(Rpc_affinity_space, Affinity::Space, affinity_space);
282 GENODE_RPC(Rpc_affinity, void, affinity, Thread_capability, Affinity::Location);
283 GENODE_RPC(Rpc_trace_control, Dataspace_capability, trace_control);
284 GENODE_RPC(Rpc_trace_control_index, unsigned, trace_control_index, Thread_capability);
285 GENODE_RPC(Rpc_trace_buffer, Dataspace_capability, trace_buffer, Thread_capability);
286 GENODE_RPC(Rpc_trace_policy, Dataspace_capability, trace_policy, Thread_capability);
287
288 /*
289 * `GENODE_RPC_INTERFACE` declaration done manually
290 *
291 * The number of RPC function of this interface exceeds the maximum
292 * number of elements supported by `Meta::Type_list`. Therefore, we
293 * construct the type list by hand using nested type tuples instead
294 * of employing the convenience macro `GENODE_RPC_INTERFACE`.
295 */
296 typedef Meta::Type_tuple<Rpc_create_thread,
297 Meta::Type_tuple<Rpc_utcb,
298 Meta::Type_tuple<Rpc_kill_thread,
299 Meta::Type_tuple<Rpc_set_pager,
300 Meta::Type_tuple<Rpc_start,
301 Meta::Type_tuple<Rpc_pause,
302 Meta::Type_tuple<Rpc_resume,
303 Meta::Type_tuple<Rpc_cancel_blocking,
304 Meta::Type_tuple<Rpc_set_state,
305 Meta::Type_tuple<Rpc_get_state,
306 Meta::Type_tuple<Rpc_exception_handler,
307 Meta::Type_tuple<Rpc_single_step,
308 Meta::Type_tuple<Rpc_affinity_space,
309 Meta::Type_tuple<Rpc_affinity,
310 Meta::Type_tuple<Rpc_trace_control,
311 Meta::Type_tuple<Rpc_trace_control_index,
312 Meta::Type_tuple<Rpc_trace_buffer,
313 Meta::Type_tuple<Rpc_trace_policy,
314 Meta::Empty>
315 > > > > > > > > > > > > > > > > > Rpc_functions;
316 };
317 }
318
319 #endif /* _INCLUDE__CPU_SESSION__CPU_SESSION_H_ */