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