]> rtime.felk.cvut.cz Git - frescor/frsh.git/blobdiff - frsh_api/frsh_thread.c
Deadline miss notification signals API changed
[frescor/frsh.git] / frsh_api / frsh_thread.c
index 24605e52d82eee0b1223fc0fc2bccdee255d40fd..b40407295d4699dfc6810e0338d29f124af8087c 100644 (file)
@@ -6,6 +6,8 @@
  *
  *
  */
+#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,
@@ -26,7 +227,7 @@ int frsh_thread_create_in_background
 {
        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);
@@ -41,15 +242,18 @@ int frsh_thread_create_in_background
                                       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
@@ -59,7 +263,12 @@ 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;
 }
@@ -79,3 +288,29 @@ int frsh_service_thread_get_data
        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;
+}