1 /**************************************************************************/
2 /* ---------------------------------------------------------------------- */
3 /* Copyright (C) 2006 - 2008 FRESCOR consortium partners: */
5 /* Universidad de Cantabria, SPAIN */
6 /* University of York, UK */
7 /* Scuola Superiore Sant'Anna, ITALY */
8 /* Kaiserslautern University, GERMANY */
9 /* Univ. Politécnica Valencia, SPAIN */
10 /* Czech Technical University in Prague, CZECH REPUBLIC */
12 /* Thales Communication S.A. FRANCE */
13 /* Visual Tools S.A. SPAIN */
14 /* Rapita Systems Ltd UK */
17 /* See http://www.frescor.org for a link to partners' websites */
19 /* FRESCOR project (FP6/2005/IST/5-034026) is funded */
20 /* in part by the European Union Sixth Framework Programme */
21 /* The European Union is not liable of any use that may be */
22 /* made of this code. */
25 /* This file is part of FRESCOR CPUCG (cpu control group) */
27 /* FWP is free software; you can redistribute it and/or modify it */
28 /* under terms of the GNU General Public License as published by the */
29 /* Free Software Foundation; either version 2, or (at your option) any */
30 /* later version. FWP is distributed in the hope that it will be */
31 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */
32 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
33 /* General Public License for more details. You should have received a */
34 /* copy of the GNU General Public License along with FWP; see file */
35 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
36 /* Cambridge, MA 02139, USA. */
38 /* As a special exception, including AQCPU header files in a file, */
39 /* instantiating FWP generics or templates, or linking other files */
40 /* with FWP objects to produce an executable application, does not */
41 /* by itself cause the resulting executable application to be covered */
42 /* by the GNU General Public License. This exception does not */
43 /* however invalidate any other reasons why the executable file might be */
44 /* covered by the GNU Public License. */
45 /**************************************************************************/
47 #include <ul_logreg.h>
48 #include <fra_generic.h>
49 #include <cpucg_res.h>
51 #include "cpucg_contract.h"
53 #include <libcgroup.h>
55 UL_LOG_CUST(ulogd_fra_cpucg);
56 ul_log_domain_t ulogd_fra_cpucg = {UL_LOGL_MSG, "fra_cpucg"};
57 UL_LOGREG_SINGLE_DOMAIN_INIT_FUNCTION(fra_cpucg_logreg_domains, ulogd_fra_cpucg);
59 static int cpucg_initialized = 0; /* initialization flag */
65 static uid_t tuid = 0;
66 static gid_t tgid = 0;
67 static uid_t cuid = 0;
68 static gid_t cgid = 0;
70 static int vres_inc = 0;
73 * Test whether Aquosa Cpu modue is initialized
75 static inline int cpucg_is_initialized()
77 return (cpucg_initialized == 1);
80 static inline char* cpucg_get_name(void)
82 char* cgname = malloc(CGNAME);
83 snprintf(cgname, CGNAME, "%d", getpid() + vres_inc++);
88 static int cpucg_create_vres(fres_vres_t *vres, void *priv)
90 cpucg_params_t cpu_params;
91 struct cgroup_controller *cpucntl;
98 /* get aqcpu params from contract */
99 get_cpucg_params(vres, &cpu_params);
100 period = cpu_params.P;
101 budget = cpu_params.Q;
103 /* create cpu vres */
104 cgroup_name = cpucg_get_name();
105 ccg = cgroup_new_cgroup(cgroup_name);
106 cgroup_set_uid_gid(ccg, tuid, tgid, cuid, cgid);
107 cpucntl = cgroup_add_controller(ccg, "cpu");
108 printf("To be Created CGCPU VRES(period=%ld us, budget=%ld us)\n",
110 cgroup_add_value_uint64(cpucntl, "cpu.rt_period_us", period);
111 cgroup_add_value_uint64(cpucntl, "cpu.rt_runtime_us", budget);
113 if ((ret = cgroup_create_cgroup(ccg, 1))) {
117 printf("Created CGCPU VRES(period=%lld us, budget=%lld us)\n",
125 * aqcpu_cancel_vres(), cancels vres
127 * The thread bound to the vres are unbound, and so, detached from their
128 * AQuoSA resource reservation servers and continue their execution according
129 * to the standard Linux scheduler policies.
132 static int cpucg_cancel_vres(fres_vres_t *vres, void *priv)
134 struct cgroup *cgroup;
141 cgroup = (struct cgroup*) vres->priv;
142 /* TODO: Solve migration
143 cgroup_delete_cgroup(cgroup, 1);*/
144 printf("Canceled CGCPU VRES\n");
145 cgroup_free(&cgroup);
150 /* aqcpu_vres_change(), change some parameters of a vres
152 * In fact, since that AQuoSA call doesn't deal with _its_ Q_min (budget_min
153 * for in FRSH semantic) parameter all the renegotiation will be accepted but
154 * the new temporal behaviour is not guaranteed!
155 * Obviously this is a bug and should/will be corrected in AQuoSA as soon as
159 int cpucg_change_vres(fres_vres_t *vres, void *priv)
161 struct cgroup *cgroup;
162 cpucg_params_t cpu_params;
169 cgroup = (struct cgroup*) vres->priv;
171 /* get aqcpu params from contract */
172 get_cpucg_params(vres, &cpu_params);
175 * cgroup->controller[0]->values[0]->value = cpu_params.P;
176 cgroup->controller[0]->values[1]->value = cpu_params.Q; */
178 ul_logmsg("AQCPU VRES params changed(period=%lld us,"
179 "budget=%lld us)\n", cpu_params.P, cpu_params.Q);
184 static int fra_CPU_bind_thread
186 const fosa_thread_id_t thread)
188 struct cgroup* cgroup = (struct cgroup*)vres->priv;
189 struct sched_param param;
192 /* if (!aqcpu_is_initialized) {
193 * return(FRSH_ERR_NOT_INITIALIZED);
197 pthread_getschedparam(pthread_self(), &policy, ¶m);
198 p = param.sched_priority;
199 printf("policy = %d, priority = %d\n", policy, p);
201 param.sched_priority = 1;
202 pthread_setschedparam(pthread_self(), SCHED_RR, ¶m);
203 pthread_getschedparam(pthread_self(), &policy, ¶m);
204 printf("changed policy = %d, changed priority = %d\n",
205 policy, param.sched_priority);
208 if (cgroup_attach_task_pid(cgroup, thread.linux_tid))
216 static int fra_CPU_unbind_thread(const fosa_thread_id_t thread)
220 /* TODO: solve thread -> vres mapping */
222 char path[FILENAME_MAX];
223 struct cgroup* cgroup = (struct cgroup*)vres->priv;
226 /* if (!aqcpu_is_initialized) {
227 * return(FRSH_ERR_NOT_INITIALIZED);
231 if (!cg_build_path(cgroup->name, path, cgroup->controller[i]->name)){
232 return FRSH_ERR_INTERNAL_ERROR;
235 strcat(path, "tasks");
236 taskf = fopen(path, "w");
238 return FRSH_ERR_INTERNAL_ERROR;
248 static int fra_CPU_get_usage
249 (const fres_vres_t *vres,
250 fosa_rel_time_t *spent)
252 return FRSH_ERR_NOT_IMPLEMENTED;
255 static int fra_CPU_get_job_usage
256 (const fres_vres_t *vres,
257 fosa_rel_time_t *spent)
259 return FRSH_ERR_NOT_IMPLEMENTED;
262 static int fra_CPU_get_remaining_budget
263 (const fres_vres_t *vres,
264 fosa_rel_time_t *budget)
266 return FRSH_ERR_NOT_IMPLEMENTED;
270 int fra_CPU_set_spare_bandwidth(fres_vres_t *vres)
272 return FRSH_ERR_NOT_IMPLEMENTED;
275 static int fra_CPU_get_desired_budget
277 frsh_rel_time_t *p_budget_out)
279 return FRSH_ERR_NOT_IMPLEMENTED;
282 static int fra_CPU_set_desired_budget
284 fosa_rel_time_t *p_budget_in)
286 return FRSH_ERR_NOT_IMPLEMENTED;
289 static int fra_CPU_get_actual_budget
291 fosa_rel_time_t *budget)
293 return FRSH_ERR_NOT_IMPLEMENTED;
296 int cpucg_fra_activate(forb_orb orb)
298 if (cpucg_is_initialized()) {
299 return FRSH_ERR_SYSTEM_ALREADY_INITIALIZED;
302 /* TODO: tets whether cpu controller is mounted */
303 //if (cgroup_init() || !cgroup_test_subsys_mounted("cpu")) {
305 return FRES_ERR_KERNEL_SUPPORT_MISSING;
308 cpucg_initialized = 1;
313 static struct fres_allocator cpucg_allocator = {
314 .res_type = FRSH_RT_PROCESSOR,
315 .res_id = 0, /* CPU ID 0 */
316 .create_vres = cpucg_create_vres,
317 .cancel_vres = cpucg_cancel_vres,
318 .change_vres = cpucg_change_vres,
320 .bind_thread = fra_CPU_bind_thread,
321 .unbind_thread = fra_CPU_unbind_thread,
323 .vres_get_usage = fra_CPU_get_usage,
324 .vres_get_job_usage = fra_CPU_get_job_usage,
325 .vres_get_remaining_budget = fra_CPU_get_remaining_budget,
327 .set_spare_bandwidth = fra_CPU_set_spare_bandwidth,
328 .get_desired_budget = fra_CPU_get_desired_budget,
329 .set_desired_budget = fra_CPU_set_desired_budget,
330 .get_actual_budget = fra_CPU_get_actual_budget,
332 .activate_callback = cpucg_fra_activate,
340 * initialize FRSH for the calling process
342 * Must be called before starting using the framework.
343 * No FRSH call will be successful if this routine is not invoked
345 * Note that no BACKGROUND is created and negotiated and the caller thread
346 * is bound to no BACKGROUND vres, since no way is provided in order of
347 * specifying the contract label and get back the vres id!
349 * Note also that, since in this implementation the threads/processes with
350 * backgound contracts are left into the default Linux scheduler hands' and
351 * not attached to any AQuoSA server, while we're violating what D-AC2v1
352 * (pag. 14) says, we achieve exactly the same behaviour!!
354 * possible return values:
356 * FRSH_ERR_ALREADY_INITIALIZED
357 * FRSH_ERR_INTERNAL_ERROR (something, different from the previous case, gone wrong)
359 int cpucg_fra_init(void)
363 cpucg_allocator.res_id = frsh_get_local_cpu_id();
365 if ((rv = fra_register(&cpucg_allocator))) {