/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
/* Cambridge, MA 02139, USA. */
/* */
-/* As a special exception, including FWP header files in a file, */
+/* As a special exception, including AQCPU header files in a file, */
/* instantiating FWP generics or templates, or linking other files */
/* with FWP objects to produce an executable application, does not */
/* by itself cause the resulting executable application to be covered */
/* however invalidate any other reasons why the executable file might be */
/* covered by the GNU Public License. */
/**************************************************************************/
+
+/**
+ * @file aqcpu_fra.c
+ * @author Martin Molnar <molnam1@fel.cvut.cz>
+ * @date Wed Feb 18 16:21:01 2009
+ *
+ * @brief
+ *
+ *
+ */
+
+
#include <ul_log.h>
+#include <ul_logreg.h>
#include <fra_generic.h>
#include "aquosa/qres_lib.h"
+#include "aquosa/qsup_lib.h"
+
#include "aqcpu_contract.h"
UL_LOG_CUST(ulogd_fra_aqcpu);
-ul_log_domain_t ulogd_fra_fwp = {UL_LOGL_DEB, "fra_aqcpu"};
+ul_log_domain_t ulogd_fra_aqcpu = {UL_LOGL_MSG, "fra_aqcpu"};
+UL_LOGREG_SINGLE_DOMAIN_INIT_FUNCTION(fra_aqcpu_logreg_domains, ulogd_fra_aqcpu);
+
+static int aqcpu_initialized = 0; /* initialization flag */
+
+/*
+ * Test whether Aquosa Cpu modue is initialized
+ */
+static inline int aqcpu_is_initialized()
+{
+ return (aqcpu_initialized == 1);
+}
+
+
static int aqcpu_create_vres(fres_vres_t *vres, void *priv)
{
- cpu_params_t cpu_params;
+ aqcpu_params_t cpu_params;
qres_sid_t sid;
qos_rv rv;
+ if (vres->priv) {
+ errno = -EINVAL;
+ return -1;
+ }
+
/* get aqcpu params from contract */
- get_aqcpu_params(vres, cpu_params);
+ get_aqcpu_params(vres, &cpu_params);
/* create cpu vres */
rv = qres_create_server(&cpu_params, &sid);
if (rv != QOS_OK) {
return qos_rv_int(rv);
}
- ul_logdeb("Created AQCPU VRES(sid=%d period=%ld us, budget=%ld us)\n",
- sid, cpu_params->P, cpu_params->Q_min);
- if (vres->priv = malloc(sizeof(qres_sid_t))) {
+ ul_logdeb("Created AQCPU VRES(sid=%d period=%lld us, budget=%lld us)\n",
+ sid, cpu_params.P, cpu_params.Q);
+ if ((vres->priv = malloc(sizeof(qres_sid_t)))) {
memcpy(vres->priv, &sid, sizeof(qres_sid_t));
}
/*
* aqcpu_cancel_vres(), cancels vres
*
- * The thread bound to the vres are unbound, and so, detached from their
- * AQuoSA resource reservation servers and continue their execution according
+ * The threads bound to the vres are unbound, and so, detached from their
+ * AQuoSA resource reservation server and continue their execution according
* to the standard Linux scheduler policies.
*
*/
qres_sid_t sid;
qos_rv qrv;
- if (vres->priv) {
+ if (!vres->priv) {
errno = -EINVAL;
return -1;
}
return qos_rv_int(qrv);
}
ul_logdeb("Canceled AQCPU VRES(sid=%d)\n",sid);
+ free(vres->priv);
+
return 0;
}
* possible.
*
*/
+static
int aqcpu_change_vres(fres_vres_t *vres, void *priv)
{
- cpu_params_t cpu_params;
+ aqcpu_params_t cpu_params;
qres_sid_t sid;
qos_rv qrv;
- if (vres->priv) {
+ if (!vres->priv) {
errno = -EINVAL;
return -1;
}
memcpy(&sid, vres->priv, sizeof(qres_sid_t));
/* get aqcpu params from contract */
- get_aqcpu_params(vres, cpu_params);
+ get_aqcpu_params(vres, &cpu_params);
/* set cpu params */
qrv = qres_set_params(sid, &cpu_params);
+
+ vres->perceived = vres->new;
+
+ ul_logmsg("AQCPU VRES(sid=%d) params changed(period=%lld us,"
+ "budget=%lld us)\n",sid, cpu_params.P,cpu_params.Q);
+
+ return 0;
+}
+
+/*
+ * installed as an exit handler (with 'atexit()') by the initialization
+ * code... For now it only calls the cleanup function of the AQuoSA
+ * Framework
+ */
+static inline void aqcpu_cleanup_wrapper() {
+ qres_cleanup();
+}
+
+#if 0
+static
+int aqcpu_fra_exit()
+{
+ qos_rv rv;
+
+ rv = qres_cleanup();
+ return qos_rv_int(rv);
+}
+#endif
+
+static
+int fra_CPU_bind_thread
+ (fres_vres_t *vres,
+ const fosa_thread_id_t thread)
+{
+ qos_rv qrv;
+ qres_sid_t sid = *((qres_sid_t*)vres->priv);
+
+ if ((qrv = qres_attach_thread(sid, thread.linux_pid,
+ thread.linux_tid)) != QOS_OK)
+ goto err;
+
+ return 0;
+err:
+ return -1;
+}
+
+static
+int fra_CPU_unbind_thread(const fosa_thread_id_t thread)
+{
+ qos_rv qrv;
+ qres_sid_t sid;
+
+ if (qres_get_sid(thread.linux_pid, thread.linux_tid, &sid) != QOS_OK)
+ goto err;
+
+ if ((qrv = qres_detach_thread(sid, thread.linux_pid,
+ thread.linux_tid)) != QOS_OK)
+ goto err;
+
+ return 0;
+err:
+ return -1;
+}
+
+static
+int fra_CPU_get_usage
+ (const fres_vres_t *vres,
+ fosa_rel_time_t *spent)
+{
+ qres_sid_t sid = *((qres_sid_t*)vres->priv);
+ qres_time_t exec_budget;
+ qos_rv rv;
+
+ if (!spent)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ rv = qres_get_exec_time(sid, &exec_budget, NULL);
+ if (rv != QOS_OK) return EINVAL;
+
+ *spent = fosa_usec_to_rel_time(exec_budget);
+
+ return 0;
+}
+
+static
+int fra_CPU_get_job_usage
+ (const fres_vres_t *vres,
+ fosa_rel_time_t *spent)
+{
+ qres_sid_t sid = *((qres_sid_t*)vres->priv);
+ qres_params_t q_params;
+ qres_time_t curr_budget;
+ qos_rv rv;
+
+ if (!spent)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ rv = qres_get_params(sid, &q_params);
+ if (rv != QOS_OK) return EINVAL;
+ rv = qres_get_curr_budget(sid, &curr_budget);
+ if (rv != QOS_OK) return EINVAL;
+
+ *spent = fosa_usec_to_rel_time(q_params.Q - curr_budget);
+
+ return 0;
+}
+
+static
+int fra_CPU_get_remaining_budget
+ (const fres_vres_t *vres,
+ fosa_rel_time_t *budget)
+{
+ qres_sid_t sid = *((qres_sid_t*)vres->priv);
+ qres_time_t curr_budget;
+ qos_rv rv;
+
+ if (!budget)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ rv = qres_get_curr_budget(sid, &curr_budget);
+ if (rv != QOS_OK) return EINVAL;
+
+ *budget = fosa_usec_to_rel_time(curr_budget);
+
+ return 0;
+}
+
+static
+int fra_CPU_set_spare_bandwidth(fres_vres_t *vres)
+{
+ qres_sid_t fake_sid = (qres_sid_t) -1;
+ aqcpu_params_t cpu_params;
+ qos_rv rv;
+
+ /* get aqcpu params from contract */
+ get_aqcpu_params(vres, &cpu_params);
+
- ul_logdeb("AQCPU VRES(sid=%d) params changed(period=%ld us,"
- "budget=%ld us)\n",sid, cpu_params->P,cpu_params->Q_min);
+ /* reserve CPU bandwidth for feedback */
+ rv = qsup_reserve_spare(r2bw(cpu_params.Q, cpu_params.P));
+ if (rv != QOS_OK) return qos_rv_int(rv);
+
+ ul_logdeb("Created AQCPU spare (period=%lld us, budget=%lld us)\n",
+ cpu_params.P, cpu_params.Q);
+ if ((vres->priv = malloc(sizeof(qres_sid_t)))) {
+ memcpy(vres->priv, &fake_sid, sizeof(qres_sid_t));
+ }
+
+ return 0;
+}
+
+static
+int fra_CPU_get_desired_budget
+ (fres_vres_t *vres,
+ frsh_rel_time_t *p_budget_out)
+{
+ qres_sid_t sid = *((qres_sid_t*)vres->priv);
+ qres_params_t q_params;
+ qos_rv rv;
+
+ if (!p_budget_out)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ rv = qres_get_params(sid, &q_params);
+ if (rv != QOS_OK) return EINVAL;
+
+ *p_budget_out = fosa_usec_to_rel_time(q_params.Q);
+
+ return 0;
+}
+
+static
+int fra_CPU_set_desired_budget
+ (fres_vres_t *vres,
+ fosa_rel_time_t *p_budget_in)
+{
+ qres_sid_t sid = *((qres_sid_t*)vres->priv);
+ qres_params_t q_params;
+ qos_rv rv;
+
+ if (!p_budget_in)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ rv = qres_get_params(sid, &q_params);
+ if (rv != QOS_OK) return EINVAL;
+
+ q_params.Q = fosa_rel_time_to_usec(*p_budget_in);
+
+ rv = qres_set_params(sid, &q_params);
+ if (rv != QOS_OK) return EINVAL;
+
+ return 0;
+}
+
+static
+int fra_CPU_get_actual_budget
+ (fres_vres_t *vres,
+ fosa_rel_time_t *budget)
+{
+ qres_sid_t sid = *((qres_sid_t*)vres->priv);
+ qres_time_t appr_budget;
+ qos_rv rv;
+
+ if (!budget)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ rv = qres_get_appr_budget(sid, &appr_budget);
+ if (rv != QOS_OK) return EINVAL;
+
+ *budget = fosa_usec_to_rel_time(appr_budget);
+
+ return 0;
+}
+
+int aqcpu_fra_activate(forb_orb orb)
+{
+ qos_rv qrv;
+ if ((qrv = qres_init()) != QOS_OK) {
+ if (qrv == QOS_E_MISSING_COMPONENT) {
+ return FRES_ERR_KERNEL_SUPPORT_MISSING;
+ } else
+ return FRSH_ERR_INTERNAL_ERROR;
+ }
+
+ /* install the cleanup function of th AQuoSA framework as an exit
+ * handler function (quite futile but, for now, it's sufficent) */
+ if (atexit(aqcpu_cleanup_wrapper)) {
+ qres_cleanup();
+ return(FRSH_ERR_INTERNAL_ERROR);
+ }
+
+ aqcpu_initialized = 1;
return 0;
}
static struct fres_allocator aqcpu_allocator = {
- .res_type = FRSH_RT_CPU,
- .res_id = 0, /* CPU ID 0 */
+ .res_type = FRSH_RT_PROCESSOR,
+ .res_id = FRSH_CPU_ID_DEFAULT, /* CPU ID 0 */
.create_vres = aqcpu_create_vres,
.cancel_vres = aqcpu_cancel_vres,
.change_vres = aqcpu_change_vres,
- .priv = NULL
-};
-int fra_aqcpu_init(forb_orb orb, fres_contract_broker fcb, forb_executor_t *executor)
-{
- if (qres_init() != QOS_OK) {
- return -1;
- }
+ .bind_thread = fra_CPU_bind_thread,
+ .unbind_thread = fra_CPU_unbind_thread,
+
+ .vres_get_usage = fra_CPU_get_usage,
+ .vres_get_job_usage = fra_CPU_get_job_usage,
+ .vres_get_remaining_budget = fra_CPU_get_remaining_budget,
+
+ .set_spare_bandwidth = fra_CPU_set_spare_bandwidth,
+ .get_desired_budget = fra_CPU_get_desired_budget,
+ .set_desired_budget = fra_CPU_set_desired_budget,
+ .get_actual_budget = fra_CPU_get_actual_budget,
+
+ .activate_callback = aqcpu_fra_activate,
- return fra_register(orb, fcb, executor, &fwp_allocator);
-}
+ .priv = NULL
+};
-int fra_aqcpu_exit()
+/*
+ * aqcpu_fra_init(), initialize FRSH for the calling process
+ *
+ * Must be called before starting using the framework.
+ * No FRSH call will be successful if this routine is not invoked
+ *
+ * Note that no BACKGROUND is created and negotiated and the caller thread
+ * is bound to no BACKGROUND vres, since no way is provided in order of
+ * specifying the contract label and get back the vres id!
+ *
+ * Note also that, since in this implementation the threads/processes with
+ * backgound contracts are left into the default Linux scheduler hands' and
+ * not attached to any AQuoSA server, while we're violating what D-AC2v1
+ * (pag. 14) says, we achieve exactly the same behaviour!!
+ */
+int aqcpu_fra_init(void)
{
- qos_rv rv;
+ int rv;
- rv = qres_cleanup();
- return qos_rv_int(rv);
+ aqcpu_allocator.res_id = frsh_get_local_cpu_id();
+
+ if ((rv = fra_register(&aqcpu_allocator))) {
+ return rv;
+ }
+
+ return 0;
}