*
*
*/
+#include <semaphore.h>
+
#include <fres_contract.h>
#include <fres_contract_idl.h>
#include <frsh_core.h>
#include <fres_blocks.h>
#include <string.h>
#include <fcb.h>
-#include "frsh_forb.h"
#include <fra_generic.h>
+#include "frsh_forb.h"
+
+#ifdef CONFIG_AQUOSA
+#include <aqcpu_res.h>
+#endif
+#ifdef CONFIG_CPUCG
+#include <cpucg_res.h>
+#endif
+#ifdef CONFIG_DISKBFQ
+#include <diskbfq_res.h>
+#endif
+
+/**
+ * frsh_thread_bind(), bind a thread to a vres
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_BAD_ARGUMENT(*) (invalid or dummy vres)
+ * FRSH_ERR_NOT_CONTRACTED_VRES(*)
+ * FRSH_ERR_ALREADY_BOUND(*)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ */
+int frsh_thread_bind
+ (const frsh_vres_id_t vres,
+ const frsh_thread_id_t thread)
+{
+ int ret;
+ ret = fra_insert_thread_vres(&thread, vres->allocator->res_type, vres);
+ if (ret) goto err;
+
+ if (vres->allocator->bind_thread) {
+ ret = vres->allocator->bind_thread(vres, thread);
+ } else {
+ ret = FRSH_ERR_NOT_IMPLEMENTED;
+ }
+ if (ret) goto err_delete;
+
+ return FRSH_NO_ERROR;
+
+err_delete:
+ fra_delete_thread_vres(&thread, vres->allocator->res_type);
+err:
+ return FRSH_ERR_INTERNAL_ERROR;
+}
+
+/*
+ * frsh_thread_unbind(), unbind a thread from a vres
+ *
+ * @FIXME:
+ * Notice that, since we don't know from which VRES the
+ * thread should be unbound, we unboind it from all the
+ * ones it is attached to!
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_BAD_ARGUMENT(*) (invalid thread)
+ * FRSH_ERR_NOT_BOUND(*)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ */
+int frsh_thread_unbind(const frsh_thread_id_t thread)
+{
+ fres_vres_t *vres;
+ int ret;
+
+ /* Unbound from FRSH_RT_PROCESSOR resource (if any) */
+ vres = fra_get_vres_thread_vres(&thread, FRSH_RT_PROCESSOR);
+ if (vres) {
+ if (vres->allocator->unbind_thread) {
+ ret = vres->allocator->unbind_thread(thread);
+ } else {
+ ret = FRSH_ERR_NOT_IMPLEMENTED;
+ }
+ if (ret) goto err;
+
+ ret = fra_delete_thread_vres(&thread, vres->allocator->res_type);
+ if (ret) goto err;
+ }
+
+ /* Unbound from FRSH_RT_DISK resource (if any) */
+ vres = fra_get_vres_thread_vres(&thread, FRSH_RT_DISK);
+ if (vres) {
+ if (vres->allocator->unbind_thread) {
+ ret = vres->allocator->unbind_thread(thread);
+ } else {
+ ret = FRSH_ERR_NOT_IMPLEMENTED;
+ }
+ if (ret) goto err;
+
+ ret = fra_delete_thread_vres(&thread, vres->allocator->res_type);
+ if (ret) goto err;
+ }
+
+ return FRSH_NO_ERROR;
+err:
+ return FRSH_ERR_INTERNAL_ERROR;
+}
+
+/**
+ * structure used to pass the new created thread (or better its wrapper) the
+ * arguments it needs to bind itself to the vres.
+ */
+typedef struct wrapper_pthread_arg {
+ frsh_thread_id_t parent_thread_id;
+ frsh_thread_id_t *thread_id;
+ frsh_thread_code_t pthread_code; /**< function to be running in thread */
+ void *pthread_arg; /**< thread arguments*/
+ frsh_vres_id_t vres;
+ sem_t *stopper; /**< semaphore to synchronize frsh call and wrapper thread */
+ int errcode;
+} wrapper_pthread_arg_t;
+
+/*
+ * typedef struct {
+ * pthread_t pthread_id;
+ * pid_t linux_pid;
+ * pid_t linux_tid;
+ * } FOSA_THREAD_ID_T_OPAQUE;
+ */
+
+/**
+ * Wrapper thread
+ *
+ * possible exit status:
+ * FRSH_ERR_INTENRAL_ERROR (something wrong with threads and signal handling)
+ * FRSH_ERR_TOO_MANY_TASKS(*)
+ * FRSH_ERR_BAD_ARGUMENT(*) (invalid vres)
+ * FRSH_ERR_NOT_CONTRACTED_VRES(*)
+ * whatever the user provided code 'pthread_code' returns
+ */
+static void* wrapper_pthread(void *arg)
+{
+ wrapper_pthread_arg_t* pth = (wrapper_pthread_arg_t*) arg;
+ frsh_thread_id_t* thread_id = pth->thread_id;
+ void *thread_arg = pth->pthread_arg;
+ frsh_thread_code_t thread_code = pth->pthread_code;
+
+ /* bind this thread to vres */
+ *thread_id = fosa_thread_self();
+ pth->errcode = frsh_thread_bind(pth->vres, *thread_id);
+
+ sem_post(pth->stopper);
+ /* No access to pth is allowed after this point, it can vanish already */
+
+ if (pth->errcode) return NULL;
+
+ /* execute thread code */
+ return thread_code(thread_arg);
+}
+
+/*
+ * API call for 'frsh_thread_create_and_bind()', as said prepares the
+ * wrapper code argument data structure, create the new thread and wait
+ * its acknowledgment before stepping over
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT (NULL thread or thread_code)
+ * whatever 'fosa_thread_create()' returns
+ * FRSH_ERR_INTERNAL_ERROR
+ */
+int frsh_thread_create_and_bind
+ (const frsh_vres_id_t vres,
+ frsh_thread_id_t *thread,
+ frsh_thread_attr_t *attr,
+ frsh_thread_code_t thread_code,
+ void *arg)
+{
+ wrapper_pthread_arg_t wp_arg;
+ sem_t stopper;
+ int ret;
+
+ sem_init(&stopper, 0, 0);
+
+ if (!thread || !thread_code || !attr)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ wp_arg.parent_thread_id = fosa_thread_self();
+ wp_arg.thread_id = thread;
+ wp_arg.pthread_code = thread_code;
+ wp_arg.pthread_arg = arg;
+ wp_arg.vres = vres;
+ wp_arg.stopper = &stopper;
+
+ /* create the wrapper thread */
+ pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
+ pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM);
+ ret = fosa_thread_create(thread, attr, wrapper_pthread,
+ (void*)&wp_arg);
+
+ if (ret != 0)
+ return(ret);
+
+ sem_wait(&stopper);
+
+ return (wp_arg.errcode);
+}
+
int frsh_thread_create_in_background
(frsh_thread_code_t thread_code,
const void *thread_arg,
{
frsh_contract_t contract;
fosa_rel_time_t zero_msec = fosa_msec_to_rel_time(0);
- int rv = 0;
+ int ret = 0;
/* Background contract creation and negotiation */
frsh_contract_init(&contract);
FRSH_CT_BACKGROUND);
/* It will be accepted: we are asking for 0 budget over 0 period */
- rv = frsh_contract_negotiate(&contract, vres_id);
- if (rv !=0) goto error;
+ ret = frsh_contract_negotiate(&contract, vres_id);
+ if (ret !=0) goto error;
- rv = fosa_thread_create(thread, attr, thread_code, (void*) thread_arg);
- if (rv != 0) goto error;
+ ret = fosa_thread_create(thread, attr, thread_code, (void*) thread_arg);
+ if (ret != 0) goto error;
+
+ ret = fra_insert_thread_vres(thread, FRSH_RT_PROCESSOR, *vres_id);
+ if (ret) goto error;
return 0;
error:
- return rv;
+ return ret;
}
int frsh_thread_get_vres_id
if (!vres_id)
return FRSH_ERR_BAD_ARGUMENT;
- *vres_id = fra_get_vres_thread_vres(&thread);
+ /*
+ * @FIXME:
+ * Why PROCESSOR and not DISK or NETWORK (or whatever) ??
+ */
+ *vres_id = fra_get_vres_thread_vres(&thread,
+ FRSH_RT_PROCESSOR);
return vres_id ? 0 : EINVAL;
}
return FRSH_ERR_NOT_IMPLEMENTED;
}
+int frsh_vres_set_notification(
+ frsh_vres_id_t vres,
+ const frsh_signal_t budget_overrun_signal,
+ const frsh_signal_info_t budget_overrun_siginfo,
+ const frsh_signal_t deadline_miss_signal,
+ const frsh_signal_info_t deadline_miss_siginfo)
+{
+ fres_block_basic *b;
+
+ /* deadline and period must be coherent between each other */
+ b = fres_contract_get_basic(vres->allocated);
+
+ /* signal delivery can only be requested for BUONDED workloads */
+ if (b &&
+ (b->workload == FRSH_WT_INDETERMINATE &&
+ (deadline_miss_signal != FRSH_NULL_SIGNAL ||
+ budget_overrun_signal != FRSH_NULL_SIGNAL)))
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ /* TODO - handle overrun and deadline signals */
+/* vres->budget_overrun_signal = budget_overrun_signal; */
+/* vres->budget_overrun_siginfo = budget_overrun_siginfo; */
+/* vres->deadline_miss_signal = deadline_miss_signal; */
+/* vres->deadline_miss_siginfo = deadline_miss_siginfo; */
+ return FRSH_ERR_NOT_IMPLEMENTED;
+}