--- /dev/null
+// -----------------------------------------------------------------------
+// Copyright (C) 2006 - 2007 by the FRESCOR consortium:
+//
+// Universidad de Cantabria, SPAIN
+// University of York, UK
+// Scuola Superiore Sant'Anna, ITALY
+// Kaiserslautern University, GERMANY
+// Univ. Politécnica Valencia, SPAIN
+// Czech Technical University in Prague, CZECH REPUBLIC
+// ENEA SWEDEN
+// Thales Communication S.A. FRANCE
+// Visual Tools S.A. SPAIN
+// Rapita Systems Ltd UK
+// Evidence ITALY
+//
+// See http://www.frescor.org
+//
+// FRESCOR project (FP6/2005/IST/5-034026) is funded
+// in part by the European Union Sixth Framework Programme
+// The European Union is not liable of any use that may be
+// made of this code.
+//
+//
+// based on previous work (FSF) done in the FIRST project
+//
+// Copyright (C) 2005 Mälardalen University, SWEDEN
+// Scuola Superiore S.Anna, ITALY
+// Universidad de Cantabria, SPAIN
+// University of York, UK
+//
+// FSF API web pages: http://marte.unican.es/fsf/docs
+// http://shark.sssup.it/contrib/first/docs/
+//
+// This file is part of FRSH API
+//
+// FRSH API is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//
+// FRSH API is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// distributed with FRSH API; see file COPYING. If not, write to the
+// Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// As a special exception, if you include this header file into source
+// files to be compiled, this header file does not by itself cause
+// the resulting executable to be covered by the GNU General Public
+// License. This exception does not however invalidate any other
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+// -----------------------------------------------------------------------
+//==============================================
+// ******** ******* ******** ** **
+// **///// /**////** **////// /** /**
+// ** /** /** /** /** /**
+// ******* /******* /********* /**********
+// **//// /**///** ////////** /**//////**
+// ** /** //** /** /** /**
+// ** /** //** ******** /** /**
+// // // // //////// // //
+//
+// FRSH(FRescor ScHeduler), pronounced "fresh"
+//==============================================
+
+/*
+ * frsh_core.c
+ *
+ * This file contains the implementation of FRSH API core functions on top
+ * of the AQuoSA framework, on GNU/Linux platform.
+ *
+ * It's the main file in which all the function are defined but many of them
+ * are implemented via a request to the service thread through a socket
+ * connection.
+ * For the details of the API functions implementation take a look
+ * into the frsh_service_th.c (and related headers) source file.
+ *
+ * The FRSH core API is actually completely implemented and almost all
+ * functions behave as described by the FRSH deliverables and specifications
+ * documents.
+ * There still could be some differences, maily due by the peculiarities of
+ * the AQuoSA framework, and they're briefly discussed in the comments leading
+ * any of the function definition and/or in separate documents
+ *
+ * The most significant issue with the actual implementation is it's limited
+ * to INDETERMINATE contracts, because of the status of the AQuoSA framework
+ * on th 2.6.x Linux platforms.
+ * Support for BOUNDED workload will came as soon as the QoS manager (qmgr) of
+ * AQuoSA will be in place
+ */
+
+/*******************/
+/* I N C L U D E S */
+/*******************/
+
+/* Linux files */
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#define __USE_UNIX98
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+/* FRSH files */
+#include "fosa.h"
+#include "frsh.h"
+#include "frsh_service_th.h"
+
+/* AQuoSA files */
+#include <aquosa/qres_lib.h>
+#include <aquosa/qsup_lib.h>
+
+/* local timepsec <-> usec utility macros */
+#include "frsh_time_extras.h"
+
+/***********************************/
+/* G L O B A L V A R I A B L E S */
+/***********************************/
+
+int frsh_initialized = 0; /* framework initialization flag */
+//#ifdef FRSH_CONFIG_ENABLE_SERVICE_TH_SAFETY_CHECK
+pid_t frsh_service_th_pid; /* service thread pid cache */
+//#endif
+
+
+/*********************************************************/
+/* U T I L I T Y F U N C T I O N A N D M A C R O S */
+/*********************************************************/
+
+
+/****************************************/
+/* CORE API IMPLEMENTATION */
+/****************************************/
+
+/////////////////////////////////////////////////
+// I N I T I A L I Z A T I O N S E R V I C E S
+/////////////////////////////////////////////////
+
+/*
+ * frsh_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!!
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_ALREADY_INITIALIZED
+ * FRSH_ERR_INTERNAL_ERROR (something, different from the previous case, gone wrong)
+ */
+
+/* forward declarations, see below ... */
+static void frsh_scheduler_signal_handler(int signum, siginfo_t *siginfo, void *cntx);
+
+static void frsh_qres_cleanup_wrapper();
+
+int frsh_aquosa_init()
+{
+ struct sigaction frsh_scheduler_signal_action;
+
+ /* check FRSH is not already initialized */
+ if (frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_SYSTEM_ALREADY_INITIALIZED,
+ "can't initialize the systema again (frsh_init already called)");
+ /* check if the name service is available and ty to start it if not */
+ if (frsh_service_th_init(&frsh_service_th_pid) != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't find nor start the FRSH service thread");
+ /* (try to) initialize the AQuoSA Framework */
+ if (qres_init() != QOS_OK || qsup_init() != QOS_OK)
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't initialize AQuoSA framework");
+ /* setup the default scheduler signal handling behaviour */
+ frsh_scheduler_signal_action.sa_sigaction = frsh_scheduler_signal_handler;
+ pthread_sigmask(0, NULL, &frsh_scheduler_signal_action.sa_mask);
+ sigaddset(&frsh_scheduler_signal_action.sa_mask, FRSH_SCHEDULER_SIGNAL); /* blocked by default */
+ pthread_sigmask(SIG_SETMASK, &frsh_scheduler_signal_action.sa_mask, NULL);
+ frsh_scheduler_signal_action.sa_flags = SA_SIGINFO | SA_RESTART;
+ if (sigaction(FRSH_SCHEDULER_SIGNAL, &frsh_scheduler_signal_action, NULL) < 0)
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't setup the signal handler for thread creation");
+
+ /* install the cleanup function of th AQuoSA framework as an exit
+ * handler function (quite futile but, for now, it's sufficent) */
+ if (atexit(frsh_qres_cleanup_wrapper))
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't install AQuoSA cleanup handler");
+ /* initialize the synchronization object repository */
+ if (!synchobj_repo_init())
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't initialize the synchronization objects");
+ /* FRSH in now initialized so that any subsequent
+ * call to this function within the same process will fail */
+ frsh_initialized = 1;
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * default signal handler for the FRSH_SCHEDULER_SIGNAL
+ *
+ * As default behaviour this function is installed as signal handler (with
+ * sa_sigaction field in the stucture) and the signal is blocked.
+ *
+ * The handler does nothing for now, but may be useful in future
+ */
+static void frsh_scheduler_signal_handler(int signum, siginfo_t *siginfo, void *cntx) {
+ if (signum != FRSH_SCHEDULER_SIGNAL)
+ PERROR_AND_EXIT(FRSH_ERR_INTERNAL_ERROR,
+ "wrong signal received while witing for FRSH_SCHEDULER_SIGNAL");
+}
+
+/*
+ * installed as an exit handler (with 'atexit()') by the initialization
+ * code... For now it only calls the cleanup function of the AQuoSA
+ * Framework
+ */
+static void frsh_qres_cleanup_wrapper() {
+ if (qres_cleanup() != QOS_OK)
+ PERROR_FRESCOR(FRSH_ERR_INTERNAL_ERROR,
+ "WARNING: error during clenup of AQuoSA framework");
+}
+
+/*
+ * frsh_thread_bind(), create a new thread and bind it to a vres
+ * frsh_thread_create_in_background(), create a new thread and a new BACKGROUND contract and bind them
+ *
+ * The two functions both create a new thread and bind it to a vres, existing
+ * fr the former, created for the latter.
+ *
+ * The implementation uses a wrapper function as the new thread code (it's
+ * the simplest way to handle some issues on POSIX 'pthread_t' and
+ * 'pthread_self()', for a detailed explanation of the "problem" ask the
+ * authors via e-mail) which, on its turn, bind itself to the vres and then
+ * run the user provided code. The API calls simply create the new thread,
+ * using the wrapper thread code, and return.
+ *
+ * Note that in order to return the caller the descriptor of the new created
+ * thread (known to the wrapped thread but not entirely to the API calls) a
+ * special 'struct' data type is passed as the parameter of the wrapper thread
+ * and a simple sinchronization mechanism based on signals is realized.
+ * Also the some of the return values are handled this way (using signals)
+ *
+ * possible return values:
+ * see below the comments of each specific API call
+ */
+
+/*
+ * structure used to pass the new created thread (or better its wrapper) the
+ * arguments it needs to bind itself to the vres.
+ *
+ * Note it also include (in 'pthread_code' and in 'pthread_arg') effective
+ * thread code and argument provided by the user to the original API
+ * 'frsh_thread_create_and_bind()' call
+ */
+typedef struct {
+ frsh_thread_id_t parent_thread_id;
+ frsh_thread_id_t *thread_id;
+ //pthread_t *pthread_pthread_id;
+ //pid_t *pthread_linux_pid;
+ //tid_t *pthread_linux_tid;
+ frsh_vres_id_t vres;
+ frsh_thread_code_t pthread_code;
+ void *pthread_arg;
+} wrapper_pthread_arg_t;
+
+/* forward declaration of the wrapper function */
+static void *wrapper_pthread_create(void *warg);
+
+/*
+ * 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 (something wrong in signal handling)
+ */
+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;
+ int thread_status;
+ //sigset_t thread_wait_mask;
+ frsh_signal_t wait_signal;
+ frsh_signal_info_t wait_signal_info;
+ struct timespec wait_signal_timeout;
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if ((thread == NULL) || (thread_code == NULL))
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't create a thread with NULL thread_core or return it in a NULL thread");
+ /*
+ * setup the wrapper code and args for the new
+ * created thread to fill in
+ *
+ * Remember:
+ * frsh_thread_id_t => struct {
+ * pthread_t pthread_id;
+ * pid_t linux_pid;
+ * tid_t linux_tid;
+ * };
+ */
+ wp.parent_thread_id = fosa_thread_self();
+ wp.thread_id = thread; /* directly fill the user provided thread descriptor pointer */
+ //wp.pthread_pthread_id = &(thread->pthread_id);
+ //wp.pthread_linux_pid = &(thread->linux_pid);
+ //wp.pthread_linux_tid = &(thread->linux_tid);
+ wp.vres = vres;
+ wp.pthread_code = thread_code;
+ wp.pthread_arg = arg;
+ /* create the wrapper thread */
+ thread_status = fosa_thread_create(NULL, attr, wrapper_pthread_create,(void*) &wp);
+ if (thread_status != 0)
+ PERROR_AND_RETURN(thread_status,
+ "can't create the new thread");
+ /* prepare a suited signal mask and wait for the new
+ * thread to acknowledge us it has filled the pointers with the descriptor*/
+ //pthread_sigmask(0, NULL, &thread_wait_mask);
+ //sigdelset(&thread_wait_mask, FRSH_SCHEDULER_SIGNAL);
+ wait_signal = FRSH_SCHEDULER_SIGNAL;
+ fosa_set_accepted_signals(&wait_signal, 1);
+ wait_signal_timeout.tv_sec = 0;
+ wait_signal_timeout.tv_nsec = 500000000; /* half a second timeout!! */
+ //if (sigsuspend(&thread_wait_mask) != -1)
+ if (fosa_signal_timedwait(&wait_signal, 1, NULL, &wait_signal_info, &wait_signal_timeout) < 0)
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't synchronize with the new created thread");
+ if (wait_signal_info.sival_int != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(wait_signal_info.sival_int,
+ "can't create and bind the new thread");
+ /* restore the signal mask to its original */
+ //sigaddset(&thread_wait_mask, FRSH_SCHEDULER_SIGNAL);
+ //pthread_sigmask(FRSH_SCHEDULER_SIGNAL, &thread_wait_mask, NULL);
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * API call for 'frsh_thread_create_in_background()', as said creates a
+ * background contract and negotiate it (we know they're always accepted
+ * but we need to get the service thread account fo the new vres), then
+ * create the new thread, exactly as seen in 'frsh_thread_create_and_bind()'
+ * and wait for its acknowledgment
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT (NULL thread_id, thread_code, contract_label or vres_id)
+ * FRSH_ERR_TOO_MANY_VRES(*)
+ * FRSH_ERR_CONTRACT_ID_ALREADY_EXISTS(*)
+ * FRSH_ERR_CONTRACT_REJECTED(*)
+ * whatever 'fosa_thread_create()' returns
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ * FRSH_ERR_INTERNAL_ERROR (something wrong in signal handling)
+ */
+int frsh_thread_create_in_background(frsh_thread_code_t thread_code,
+ const void *thread_arg,
+ const frsh_contract_label_t contract_label,
+ frsh_thread_attr_t *attr,
+ frsh_thread_id_t *thread_id,
+ frsh_vres_id_t *vres_id)
+{
+ frsh_contract_t contract;
+ frsh_in_msg_t contract_msg;
+ frsh_out_msg_t vres_msg;
+
+ wrapper_pthread_arg_t wp;
+ int thread_status;
+ //sigset_t thread_wait_mask;
+ frsh_signal_t wait_signal;
+ frsh_signal_info_t wait_signal_info;
+ frsh_rel_time_t wait_signal_timeout;
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if ((thread_code == NULL) || (thread_id == NULL))
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't create a thread with NULL thread_code or return it in a NULL thread_id");
+ if (contract_label == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't give the contract a NULL contract_label");
+ if (vres_id == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't negotiate for a NULL vres_id");
+
+ /* initialize a contract core parameters
+ * exactly as if we've called 'frsh_contract_init()' */
+ /* Core contract attributes setup */
+ contract.resource_id = FRSH_RESOURCE_ID_DEFAULT;
+ contract.resource_type = FRSH_RT_PROCESSOR;
+ /* contract.contract_label not modified/initialized */
+ contract.budget_min = FOSA_USEC_TO_REL_TIME(0);
+ contract.period_max = FOSA_USEC_TO_REL_TIME(0);
+ contract.workload = FRSH_WT_INDETERMINATE;
+ contract.contract_type = FRSH_CT_REGULAR;
+ contract.d_equals_t = true;
+ contract.deadline = FOSA_USEC_TO_REL_TIME(0);
+ contract.budget_overrun_signal = FRSH_NULL_SIGNAL;
+ contract.budget_overrun_siginfo.sival_int = 0;
+ contract.deadline_miss_signal = FRSH_NULL_SIGNAL;
+ contract.deadline_miss_siginfo.sival_int = 0;
+ /* setup id parameters of the contract
+ * as if we've called 'frsh_contract_set_resource_and_label()' */
+ contract.resource_type = FRSH_RT_PROCESSOR;
+ contract.resource_id = FRSH_RESOURCE_ID_DEFAULT;
+ strncpy(contract.contract_label, contract_label, FRSH_CONTRACT_LABEL_MAXLENGTH);
+ /* setup basic contract parameters
+ * (in order to specify it's a background contract!)
+ * as if we've called 'frsh_contract_set_basic_params()' */
+ contract.workload = FRSH_WT_INDETERMINATE;
+ contract.contract_type = FRSH_CT_BACKGROUND;
+ /* setup additional timing parameters for the contract
+ * as if we've called 'frsh_contract_set_timing_reqs()' */
+ contract.d_equals_t = true;
+ /* ask the service thread for the contract negotiation
+ * (as if we've called 'frsh_contract_negotiate()') */
+ /* prepare the message */
+ contract_msg.type = FRSH_MT_NEGOTIATE_CONTRACT;
+ contract_msg.val.negotiate_contract.contract = contract;
+ /* contact the service thread for contract negotiation */
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &contract_msg, &vres_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ if (vres_msg.error != FRSH_NO_ERROR)
+ /* possible return values are listed in the description
+ * of the function upward (the one marked with '(*)') */
+ PERROR_AND_RETURN(vres_msg.error,
+ "can't negotiate the new background contract");
+ *vres_id = vres_msg.val.negotiate_contract.vres_id;
+ /* create a new thread with the described wrapper
+ * as thread code in order to handle the binding to the
+ * just created background vres (and to signal us when it's done!)*/
+ wp.parent_thread_id = fosa_thread_self();
+ wp.thread_id = thread_id; /* directly fill the user provided thread descriptor pointer */
+ //wp.pthread_pthread_id = &(thread_id->pthread_id);
+ //wp.pthread_linux_pid = &(thread_id->linux_pid);
+ //wp.pthread_linux_tid = &(thread_id->linux_tid);
+ wp.vres = *vres_id;
+ wp.pthread_code = thread_code;
+ wp.pthread_arg = (void*) thread_arg;
+ /* create the wrapper thread */
+ thread_status = fosa_thread_create(NULL, attr, wrapper_pthread_create,(void*) &wp);
+ if (thread_status != 0)
+ PERROR_AND_RETURN(thread_status,
+ "can't create the new background thread");
+ /* prepare a suited signal mask and wait for the new
+ * thread to acknowledge us it has filled the pointers with the descriptor*/
+ //pthread_sigmask(0, NULL, &thread_wait_mask);
+ //sigdelset(&thread_wait_mask, FRSH_SCHEDULER_SIGNAL);
+ wait_signal = FRSH_SCHEDULER_SIGNAL;
+ fosa_set_accepted_signals(&wait_signal, 1);
+ /* half a second timeout!! */
+ wait_signal_timeout = FOSA_USEC_TO_REL_TIME(500000);
+ //if (sigsuspend(&thread_wait_mask) != -1)
+ if (fosa_signal_timedwait(&wait_signal, 1, NULL, &wait_signal_info, &wait_signal_timeout) < 0)
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't synchronize with the new created background thread");
+ if (wait_signal_info.sival_int != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(wait_signal_info.sival_int,
+ "can't create and bind the new background thread");
+ /* restore the signal mask to its original */
+ //sigaddset(&thread_wait_mask, FRSH_SCHEDULER_SIGNAL);
+ //pthread_sigmask(FRSH_SCHEDULER_SIGNAL, &thread_wait_mask, NULL);
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * code for the described wrapper, it only asks the service thread the
+ * binding of itself to the vres and the directly run the user provided
+ * thread code.
+ *
+ * Note that some of the return values of the API
+ * 'frsh_thread_create_and_bind()' or 'frsh_thread_create_in_background()'
+ * call are also possible exit status of the new thread
+ *
+ * possible exit status:
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread)
+ * 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_create(void *warg)
+{
+ frsh_in_msg_t bind_msg;
+ frsh_out_msg_t vres_msg;
+ frsh_signal_info_t frsh_status_siginfo;
+
+ /* fill both local and on the calling thread descriptor */
+ wrapper_pthread_arg_t pth = *((wrapper_pthread_arg_t*) warg);
+ *(pth.thread_id) = fosa_thread_self();
+ //*(pth.pthread_pthread_id) = this_thread.pthread_id;
+ //*(pth.pthread_linux_pid) = this_thread.linux_pid;
+ //*(pth.pthread_linux_tid) = this_thread.linux_tid;
+ /* prepare the message */
+ bind_msg.type = FRSH_MT_BIND_THREAD;
+ bind_msg.val.bind_thread.thread_id = *(pth.thread_id);
+ bind_msg.val.bind_thread.vres_id = pth.vres;
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &bind_msg,&vres_msg) != FRSH_SERVICE_TH_NO_ERROR) {
+ PERROR_FRESCOR(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ pthread_exit((void*) FRSH_ERR_INVALID_SCHEDULER_REPLY); // move to fosa_???
+ }
+ if (vres_msg.error != FRSH_NO_ERROR) {
+ PERROR_FRESCOR(vres_msg.error, "can't bind to the vres");
+ pthread_exit((void*) vres_msg.error); // move to fosa_???
+ }
+ /* signal our 'creator' we've filled the pointers
+ * it needs and we've (at least tried to) bound ourself */
+ frsh_status_siginfo.sival_int = vres_msg.error;
+ if (fosa_signal_queue(FRSH_SCHEDULER_SIGNAL, frsh_status_siginfo, pth.parent_thread_id) < 0) {
+ PERROR_FRESCOR(FRSH_ERR_INTERNAL_ERROR,
+ "can't acknowledge the new thread creation");
+ pthread_exit((void*) FRSH_ERR_INTERNAL_ERROR); // move to fosa_???
+ }
+
+ return pth.pthread_code(pth.pthread_arg);
+}
+
+/*
+ * frsh_thread_bind(), bind a thread to a vres
+ *
+ * Asks the service thread for binding of a thread to a valid, REGULAR and
+ * contracetd vres.
+ * If all is ok the thread is attached to an AQuoSA resource reservation server
+ *
+ * As usual the code below simply prepares a message, send it and wait for
+ * the answer from the service thread, for details on the implementation check
+ * 'bind_thread()' in the frsh_service_th.c source file
+
+ * 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)
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread)
+ */
+int frsh_thread_bind(const frsh_vres_id_t vres, const frsh_thread_id_t thread)
+{
+ frsh_in_msg_t bind_msg;
+ frsh_out_msg_t vres_msg;
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ /* prepare the message */
+ bind_msg.type = FRSH_MT_BIND_THREAD;
+ bind_msg.val.bind_thread.thread_id = thread;
+ bind_msg.val.bind_thread.vres_id = vres;
+ /* contact the service thread for bind the thread */
+ if (frsh_service_th_ask_for(frsh_service_th_pid,&bind_msg,&vres_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ if (vres_msg.error != FRSH_NO_ERROR)
+ /* possible return values are listed in the description
+ * of the function upward (the one marked with '(*)') */
+ PERROR_AND_RETURN(vres_msg.error,
+ "can't bind the thread");
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_thread_unbind(), unbind a thread from a vres
+ *
+ * Asks the service thread for revoke the binding of a thread to a its actual
+ * vres.
+ * If all is ok the thread is detached from the AQuoSA resource
+ * reservation server.
+ *
+ * The code below only prepares the message, send it and wait for the answer,
+ * for details on the implementation check 'unbind_thread()' in the
+ * frsh_service_th.c source file
+
+ * 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)
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread)
+ */
+int frsh_thread_unbind(const frsh_thread_id_t thread)
+{
+ frsh_in_msg_t unbind_msg;
+ frsh_out_msg_t reply_msg;
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ /* prepare the message */
+ unbind_msg.type = FRSH_MT_UNBIND_THREAD;
+ unbind_msg.val.unbind_thread.thread_id = thread;
+ /* contact the service thread for unbind the thread */
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &unbind_msg, &reply_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ if (reply_msg.error != FRSH_NO_ERROR)
+ /* possible return values are listed in the description
+ * of the function upward (the one marked with '(*)') */
+ PERROR_AND_RETURN(reply_msg.error,
+ "can't unbind the thread");
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_thread_get_vres_id(), get the id vres of a vres bound to a thread
+ *
+ * Asks the service thread for the id of a particular vres, knowing the thread
+ * bound to it.
+ *
+ * The code below only prepares the message, send it and wait for the answer,
+ * for details on the implementation check 'get_thread_vres_id()' in the
+ * frsh_service_th.c source file
+
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_BAD_ARGUMENT(*) (invalid thread or NULL vres)
+ * FRSH_ERR_NOT_BOUND(*) (-IMPOSSIBLE- thread not bound)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread)
+ */
+int frsh_thread_get_vres_id(const frsh_thread_id_t thread,
+ frsh_vres_id_t *vres_id)
+{
+ frsh_in_msg_t thread_msg;
+ frsh_out_msg_t vres_msg;
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (vres_id == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't return the id in a NULL vres_id");
+ /* prepare the message */
+ thread_msg.type = FRSH_MT_GET_THREAD_VRES_ID;
+ thread_msg.val.get_thread_vres_id.thread_id = thread;
+ /* contact the service thread for the vres id */
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &thread_msg, &vres_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ if (vres_msg.error != FRSH_NO_ERROR)
+ /* possible return values are listed in the description
+ * of the function upward (the one marked with '(*)') */
+ PERROR_AND_RETURN(vres_msg.error,
+ "can't get the vres id");
+ /* store the vres id only now so, if something
+ * goes wrong, the vres_id pointer is returned untouched */
+ *vres_id = vres_msg.val.get_thread_vres_id.vres_id;
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_thread_self(), get the thread and vres id of the caller
+ *
+ * Simply returns the thread id of the caller and the vres id to which
+ * (if any) it's bound.
+ *
+ * Note that the thread id is always returned, while the retrieval of the vres
+ * id can be skipped passing a NULL pointer as vres_self argument.
+ *
+ * Nota also that the thread id could be retieved via a simple FOSA call, while
+ * for the vres id we can only ask it to the service thread.
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT (NULL thread_self)
+ * all that 'frsh_thread_get_vres_id()' returns (FRSH_ERR_NOT_BOUND)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread)
+ */
+//int frsh_thread_self(frsh_thread_id_t *thread_self, frsh_vres_id_t *vres_self)
+//{
+// frsh_in_msg_t thread_msg;
+// frsh_out_msg_t vres_msg;
+//
+// /* check for framework initialization and arguments */
+// if (!frsh_initialized)
+// PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+// "can't proceed before initializing FRSH with 'frsh_init()'!");
+// if (thread_self == NULL)
+// PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+// "can't put self thread id in a NULL thread_self");
+// /* get the thread id of ourself */
+// *thread_self = fosa_thread_self();
+// /* get, if requested, even the vres id of ourself */
+// if (vres_self != NULL) {
+// /* prepare the message */
+// thread_msg.type = FRSH_MT_GET_THREAD_VRES_ID;
+// thread_msg.val.get_thread_vres_id.thread_id = *thread_self;
+// /* contact the service thread for the vres id */
+// if (frsh_service_th_ask_for(frsh_service_th_pid, &thread_msg, &vres_msg) != FRSH_SERVICE_TH_NO_ERROR)
+// PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+// "can't receive correct answer from the service thread");
+// if (vres_msg.error != FRSH_NO_ERROR)
+// /* possible return values are listed in the description
+// * of the function upward (the one marked with '(*)') */
+// PERROR_AND_RETURN(vres_msg.error,
+// "can't get the vres id of the calling thread");
+// /* vres_self pointer untouched if not all gone well */
+// *vres_self = vres_msg.val.get_thread_vres_id.vres_id;
+// }
+//
+// return FRSH_NO_ERROR;
+//}
+
+/*
+ * frsh_vres_get_contract(), get the contract associated to a vres
+ *
+ * Simply returns contract associated to a valid (and contracted!) vres.
+ *
+ * As usual only prepares the message, send it and wait for the answer,
+ * for details on the implementation check 'get_contract()' in the
+ * frsh_service_th.c source file
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT (NULL contract)
+ * FRSH_ERR_BAD_ARGUMENT(*) (invalid vres)
+ * FRSH_ERR_NOT_CONTRACTED_VRES(*)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread)
+ */
+int frsh_vres_get_contract(const frsh_vres_id_t vres, frsh_contract_t *contract)
+{
+ frsh_in_msg_t vres_msg;
+ frsh_out_msg_t contract_msg;
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (contract == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't return contract parameters in a NULL contract");
+ /* prepare the message */
+ vres_msg.type = FRSH_MT_GET_CONTRACT;
+ vres_msg.val.get_contract.vres_id = vres;
+ /* contact the service thread for the contract */
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &vres_msg, &contract_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ if (contract_msg.error != FRSH_NO_ERROR)
+ /* possible return values are listed in the description
+ * of the function upward (the one marked with '(*)') */
+ PERROR_AND_RETURN(contract_msg.error,
+ "can't get the contract");
+ /* contract pointer untouched if something has gone wrong */
+ *contract = contract_msg.val.get_contract.contract;
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_resource_get_vres_from_label(), get a contracted vres id from the label of the contract
+ *
+ * Returns the id of a contracted vres using as a search key the label of
+ * the contract, provided it's valid!
+ *
+ * As usual only prepares the message, send it and wait for the answer,
+ * for details on the implementation check 'get_label_vres_id()' in the
+ * frsh_service_th.c source file
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT (NULL vres or contract label)
+ * FRSH_ERR_BAD_ARGUMENT(*) (unknown contract label)
+ * //FRSH_ERR_CONTRACT_LABEL_UNKNOWN(*) (unknown contract label)
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread)
+ * FRSH_ERR_NOT_IMPLEMENTED
+ */
+int frsh_resource_get_vres_from_label(const frsh_contract_label_t contract_label,
+ const frsh_resource_type_t resource_type,
+ const frsh_resource_id_t resource_id,
+ frsh_vres_id_t *vres)
+{
+ frsh_in_msg_t label_msg;
+ frsh_out_msg_t vres_msg;
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (contract_label == NULL || vres == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't search for a NULL contract_label or return id in a NULL vres");
+ /* this implementation is limited to processor type of resources */
+ if (resource_type != FRSH_RT_PROCESSOR ||
+ resource_id != FRSH_RESOURCE_ID_DEFAULT)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_IMPLEMENTED,
+ "can't handle resource types different from PROCESSOR with DEFAULT id ones");
+ /* prepare the message */
+ label_msg.type = FRSH_MT_GET_LABEL_VRES_ID;
+ strncpy(label_msg.val.get_label_vres_id.contract_label, contract_label, FRSH_CONTRACT_LABEL_MAXLENGTH);
+ /* contact the service thread for the vres */
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &label_msg, &vres_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ if (vres_msg.error != FRSH_NO_ERROR)
+ /* possible return values are listed in the description
+ * of the function upward (the one marked with '(*)') */
+ PERROR_AND_RETURN(vres_msg.error,
+ "can't get the vres");
+ /* vres pointer untouched if something has gone wrong */
+ *vres = vres_msg.val.get_label_vres_id.vres_id;
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_contract_cancel(), remove a contract and destroy the vres
+ *
+ * Asks the service thread for the elimination of a previously negotiated
+ * contract and the destruction of the associated vres, causing all the
+ * bounded thread to unbind themself from it.
+ *
+ * The code below simply prepares the message for the service thread, then
+ * send it and wait untill a response is received. For detailed
+ * implementation analysis check the function 'cancel_contract()' in the
+ * frsh_service_th.c source file
+ *
+ * Note that in this implementation if a vres is destroyed and all bounded
+ * thread are unbound they don't automatically stop their execution (as
+ * the FRSH docs seems to suggest), they simply get re-attached to the
+ * standard Linux scheduler and start running outside from the AQuoSA
+ * framework and with no more guarantees.
+ *
+ * Note also that if this call fails we can not guess if the vres has
+ * effectively been destroyed, if the thread have been unbound, ecc. and
+ * it's usually not safe (as in all other cases?!?!) to continue running
+ * the program making some kind of (surely wrong!!) assumption
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT(*) (invalid vres)
+ * FRSH_ERR_NOT_CONTRACTED_VRES(*)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread)
+ */
+int frsh_contract_cancel(const frsh_vres_id_t vres)
+{
+ frsh_in_msg_t vres_msg;
+ frsh_out_msg_t reply_msg;
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ /* prepare the message */
+ vres_msg.type = FRSH_MT_CANCEL_CONTRACT;
+ vres_msg.val.cancel_contract.vres_id = vres;
+ /* contact the service thread for the contract cancellation */
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &vres_msg, &reply_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ if (reply_msg.error != FRSH_NO_ERROR)
+ /* possible return values are listed in the description
+ * of the function upward (the one marked with '(*)') */
+ PERROR_AND_RETURN(reply_msg.error,
+ "can't cancel the contract");
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_contract_renegotiate_sync(), try to change the parameters of a contract
+ *
+ * Tries to change the parameters of a contract requesting a new negotiation
+ * and waits until the request is satisfied or refused.
+ * As requested by the API specs the old contract parameters remain valid if
+ * the renegotiation fails (which actually won't never happen!! See below)
+ *
+ * All parameters of a contract can be changed, included it's label, but,
+ * since we can't create (and return the id to the caller) a new vres,
+ * it's forbidden to change the contract type.
+ * So REGULAR contract can't become DUMMY or BACKGROUND but must stay REGULAR
+ * (an so on with the other types)
+ *
+ * Note also that, actually, there are some "little" issues with the AQuoSA
+ * implementation of the "parameter changing" of servers and, since this is
+ * only the simple code that handle request/response to/from the service
+ * thread, you've got to check the comments and the code of
+ * 'renegotiate_contract()' in the frsh_service_th.c source file for more
+ * details
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT (NULL new_contract)
+ * FRSH_ERR_BAD_ARGUMENT(*) (invalid vres or trying to change the contract type)
+ * FRSH_ERR_CONTRACT_ID_ALREADY_EXISTS(*) (new contract label already exists)
+ * FRSH_ERR_NOT_CONTRACTED_VRES(*)
+ * FRSH_ERR_CONTRACT_REJECTED(*)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread)
+ */
+int frsh_contract_renegotiate_sync(const frsh_contract_t *new_contract,
+ const frsh_vres_id_t vres)
+{
+ frsh_in_msg_t contract_msg;
+ frsh_out_msg_t reply_msg;
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (new_contract == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't renegotiate to a NULL new_contract");
+ /* actual limits of this implementation */
+ if (!new_contract->d_equals_t ||
+ new_contract->workload != FRSH_WT_INDETERMINATE)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_IMPLEMENTED,
+ "can't setup deadline different from period within this implementation");
+ /* prepare the message */
+ contract_msg.type = FRSH_MT_RENEGOTIATE_CONTRACT;
+ contract_msg.val.renegotiate_contract.new_contract = *new_contract;
+ contract_msg.val.renegotiate_contract.vres_id = vres;
+ /* contact the service thread for the contract renegotiation */
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &contract_msg, &reply_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ if (reply_msg.error != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(reply_msg.error,
+ "can't renegotiate the contract");
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_contract_renegotiate_async(), try to change the parameters of a contract but don't wait the exitus
+ *
+ * Exactly equal to previous function ('frsh_contract_renegotiate_sync()')
+ * tries to change the parameters of a contracted vres via the negotiation of
+ * a new contract for it.
+ *
+ * The only difference is here we don't wait for the service thread to handle
+ * our request and answer, we simply step forward, eventually asking for a
+ * signal to be delivered (if the service thread is running on the same
+ * machine of us!) at job completion.
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread)
+ */
+int frsh_contract_renegotiate_async(const frsh_contract_t *new_contract,
+ const frsh_vres_id_t vres,
+ const frsh_signal_t signal_to_notify,
+ const frsh_signal_info_t signal_info)
+
+{
+ frsh_in_msg_t contract_msg;
+ frsh_out_msg_t reply_msg;
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (new_contract == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't request a renegotiation to a NULL new_contract");
+ /* actual limits of this implementation */
+ if (!new_contract->d_equals_t ||
+ new_contract->workload != FRSH_WT_INDETERMINATE)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_IMPLEMENTED,
+ "can't setup deadline different from period within this implementation");
+ /* prepare the message */
+ contract_msg.type = FRSH_MT_REQUEST_CONTRACT_RENEGOTIATION;
+ contract_msg.val.request_contract_renegotiation.new_contract = *new_contract;
+ contract_msg.val.request_contract_renegotiation.vres_id = vres;
+#ifdef FRSH_CONFIG_SERVICE_TH_LOCAL_MACHINE
+ contract_msg.val.request_contract_renegotiation.signal = signal_to_notify;
+ contract_msg.val.request_contract_renegotiation.siginfo = signal_info;
+ contract_msg.val.request_contract_renegotiation.thread_to_signal = fosa_thread_self();
+#endif
+ /* contact the service thread for the contract renegotiation */
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &contract_msg, &reply_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ /* the reply mesage has no sense here since the
+ * service thread does not process our request synchronously */
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_vres_get_renegotiation_status(), obtain the status of the last renegotiation operation
+ *
+ * Simply returns the actual renegotiation status of a vres, as reported
+ * by the service thread.
+ *
+ * As usual only prepares the message, send it and wait for the answer,
+ * for details on the implementation check 'get_renegotiation_status()'
+ * in the frsh_service_th.c source file
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT (NULL renegotiation_status)
+ * FRSH_ERR_BAD_ARGUMENT(*) (invalid vres)
+ * FRSH_ERR_NOT_CONTRACTED_VRES(*)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread)
+ */
+int frsh_vres_get_renegotiation_status (const frsh_vres_id_t vres,
+ frsh_renegotiation_status_t *renegotiation_status)
+{
+ frsh_in_msg_t vres_msg;
+ frsh_out_msg_t status_msg;
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (renegotiation_status == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't return status in a NULL renegotiation_status");
+ /* prepare the message */
+ vres_msg.type = FRSH_MT_GET_RENEGOTIATION_STATUS;
+ vres_msg.val.get_renegotiation_status.vres_id = vres;
+ /* contact the service thread for the contract renegotiation */
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &vres_msg, &status_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ if (status_msg.error != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(status_msg.error,
+ "can't get the renegotiation status");
+ /* renegotiation_stratus pointer untouched if something has gone wrong */
+ *renegotiation_status = status_msg.val.get_renegotiation_status.renegotiation_status;
+
+ return FRSH_NO_ERROR;
+}
+
+/////////////////////////////////////////////////////////////
+// G R O U P O F C O N T R A C T S O P E R A T I O N S
+/////////////////////////////////////////////////////////////
+
+int contracts_up_status[FRSH_MAX_N_VRES]; // should be one of the functions output parameter for this implementation
+int vres_touch_status[FRSH_MAX_N_VRES]; // should be one of the functions output parameter for this implementation
+int vres_down_status[FRSH_MAX_N_VRES]; // should be one of the functions output parameter for this implementarion
+
+/*
+ * frsh_group_negotiate()
+ *
+ * ...
+ */
+int frsh_group_negotiate (const frsh_contracts_group_t *contracts_up,
+ const frsh_vres_group_t *vres_down,
+ frsh_vres_group_t *vres_up)
+{
+ frsh_in_msg_t contract_msg;
+ frsh_out_msg_t vres_msg;
+ int i;
+
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "place a call frsh_init first!");
+ if (contracts_up == NULL && vres_down == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "could not negotiate/cancel a NULL contract or vres group");
+ if (vres_up == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't negotiate for a NULL vres group");
+ /* contact the service thread for contract negotiation */
+ contract_msg.type = FRSH_MT_NEGOTIATE_GROUP;
+ if (contracts_up != NULL)
+ for (i = 0; i < contracts_up->size; i++) {
+ if (contracts_up->contracts[i] == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "could not negotiate a NULL contract in the group");
+ if (!contracts_up->contracts[i]->d_equals_t) // limited by by this implementation
+ PERROR_AND_RETURN(FRSH_ERR_NOT_IMPLEMENTED,
+ "only deadline=period implemented!");
+ contract_msg.val.negotiate_group.contracts_up[i] = *(contracts_up->contracts[i]);
+ }
+ contract_msg.val.negotiate_group.contracts_up_number = contracts_up->size;
+ if (vres_down != NULL)
+ for (i = 0; i < vres_down->size; i++)
+ contract_msg.val.negotiate_group.vres_down[i] = vres_down->vres[i];
+ contract_msg.val.negotiate_group.vres_down_number = vres_down->size;
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &contract_msg, &vres_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY, // it's _service_ thread, not scheduler !!
+ "service thread not/wrong responding");
+ for (i = 0; i < contracts_up->size; i++) {
+ contracts_up_status[i] = vres_msg.val.negotiate_group.contracts_up_status[i];
+ vres_up->vres[i] = vres_msg.val.negotiate_group.vres_up[i];
+ }
+ vres_up->size = contracts_up->size;
+ for (i = 0; i < vres_down->size; i++)
+ vres_down_status[i] = vres_msg.val.negotiate_group.vres_down_status[i];
+ if (vres_msg.error != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(vres_msg.error, "error(s) during contract negotiation/cancellation");
+
+ return FRSH_NO_ERROR;
+}
+
+int change_mode(bool sync,
+ const frsh_contracts_group_t *contracts_new_vres,
+ frsh_vres_group_t *vres_id_new,
+ const frsh_contracts_group_t *contracts_update_vres,
+ const frsh_vres_group_t *vres_update,
+ const frsh_vres_group_t *vres_removed,
+ frsh_signal_t signal_notify,
+ frsh_signal_info_t signal_info);
+
+/*
+ * frsh_group_change_mode_sync()
+ *
+ * ...
+ */
+int frsh_group_change_mode_sync(const frsh_contracts_group_t *contracts_new_vres,
+ frsh_vres_group_t *vres_id_new,
+ const frsh_contracts_group_t *contracts_update_vres,
+ const frsh_vres_group_t *vres_update,
+ const frsh_vres_group_t *vres_removed)
+{
+ frsh_signal_info_t null_siginfo;
+
+ null_siginfo.sival_int = 0;
+
+ return change_mode(true, contracts_new_vres, vres_id_new,
+ contracts_update_vres, vres_update, vres_removed,
+ FRSH_NULL_SIGNAL, null_siginfo);
+}
+
+/*
+ * frsh_group_change_mode_async()
+ *
+ * ...
+ */
+int frsh_group_change_mode_async(const frsh_contracts_group_t *contracts_new_vres,
+ frsh_vres_group_t *vres_id_new,
+ const frsh_contracts_group_t *contracts_update_vres,
+ const frsh_vres_group_t *vres_update,
+ const frsh_vres_group_t *vres_removed,
+ const frsh_signal_t signal_notify,
+ const frsh_signal_info_t signal_info)
+
+{
+ // new_contract_labels ???
+ return change_mode(false, contracts_new_vres, vres_id_new,
+ contracts_update_vres, vres_update, vres_removed,
+ signal_notify, signal_info);
+}
+
+int change_mode(bool sync,
+ const frsh_contracts_group_t *contracts_up,
+ frsh_vres_group_t *vres_up,
+ const frsh_contracts_group_t *new_contracts_touch,
+ const frsh_vres_group_t *vres_touch,
+ const frsh_vres_group_t *vres_down,
+ frsh_signal_t signal_notify,
+ frsh_signal_info_t signal_info)
+{
+ frsh_in_msg_t contract_msg;
+ frsh_out_msg_t vres_msg;
+ int i;
+
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "place a call frsh_init first!");
+ if ((new_contracts_touch == NULL && vres_touch != NULL) ||
+ (new_contracts_touch != NULL && vres_touch == NULL))
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "inconsistent status of contracts and vres groups to be renengotiated");
+ if (new_contracts_touch != NULL &&
+ vres_touch != NULL &&
+ new_contracts_touch->size != vres_touch->size)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "inconsistent status of contracts and vres groups to be renengotiated");
+ if (contracts_up == NULL &&
+ new_contracts_touch == NULL &&
+ vres_down == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "nothing to do!");
+ if (!sync &&
+ ((vres_touch != NULL && vres_touch->size == 0) &&
+ (vres_down != NULL && vres_down->size == 0)))
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "at least one renegotiation or cancellation needed");
+ /* contact the service thread for contract negotiation */
+ if (sync)
+ contract_msg.type = FRSH_MT_CHANGE_MODE_SYNC;
+ else
+ contract_msg.type = FRSH_MT_CHANGE_MODE_ASYNC;
+ if (contracts_up != NULL)
+ for (i = 0; i < contracts_up->size; i++) {
+ if (contracts_up->contracts[i] == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "could not negotiate a NULL contract in the group");
+ if (!contracts_up->contracts[i]->d_equals_t) // limited by by this implementation
+ PERROR_AND_RETURN(FRSH_ERR_NOT_IMPLEMENTED,
+ "only deadline=period implemented!");
+ contract_msg.val.change_mode.contracts_up[i] = *(contracts_up->contracts[i]);
+ }
+ contract_msg.val.change_mode.contracts_up_number = contracts_up->size;
+ if (new_contracts_touch != NULL)
+ for (i = 0; i < new_contracts_touch->size; i++) {
+ if (new_contracts_touch->contracts[i] == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "could not change mode for a NULL contract");
+ if (!new_contracts_touch->contracts[i]->d_equals_t)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_IMPLEMENTED,
+ "only deadline=period implemented!");
+ contract_msg.val.change_mode.contracts_touch[i] = *(new_contracts_touch->contracts[i]);
+ contract_msg.val.change_mode.vres_touch[i] = vres_touch->vres[i];
+ }
+ contract_msg.val.change_mode.contracts_touch_number = new_contracts_touch->size;
+ if (vres_down != NULL)
+ for (i = 0; i < vres_down->size; i++)
+ contract_msg.val.negotiate_group.vres_down[i] = vres_down->vres[i];
+ contract_msg.val.negotiate_group.vres_down_number = vres_down->size;
+#ifdef FRSH_CONFIG_SERVICE_TH_LOCAL_MACHINE
+ contract_msg.val.change_mode.signal = signal_notify;
+ contract_msg.val.change_mode.siginfo = signal_info;
+ contract_msg.val.change_mode.thread_to_signal = fosa_thread_self();
+#endif
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &contract_msg, &vres_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY, // it's _service_ thread, not scheduler !!
+ "service thread not/wrong responding");
+ for (i = 0; i < contracts_up->size; i++) {
+ contracts_up_status[i] = vres_msg.val.change_mode.contracts_up_status[i];
+ vres_up->vres[i] = vres_msg.val.change_mode.vres_up[i];
+ }
+ for (i = 0; i < new_contracts_touch->size; i++)
+ vres_touch_status[i] = vres_msg.val.change_mode.vres_touch_status[i];
+ for (i = 0; i < vres_down->size; i++)
+ vres_down_status[i] = vres_msg.val.change_mode.vres_down_status[i];
+ if (sync)
+ if (vres_msg.error != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(vres_msg.error, "error(s) during contract negotiation/cancellation");
+
+ return FRSH_NO_ERROR;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// O B T A I N I N F O R M A T I O N S F R O M T H E S C H E D U L E R
+////////////////////////////////////////////////////////////////////////////////
+
+/*
+ * frsh_config_is_admission_test_enabled()
+ *
+ * Tell the caller if the admission test is enabled... And it's always enabled
+ * in this implementation!
+ *
+ * possible return values:
+ * true
+ */
+bool frsh_config_is_admission_test_enabled()
+{
+ /* admission test is always enabled in this implementation */
+ return true;
+}
+
+/*
+ * frsh_vres_get_usage()
+ *
+ * Obtains from the service thread the CPU usage count of a vres.
+ *
+ * Note this service is only available for vres with a REGULAR contract type.
+ *
+ * As usual only prepares the message, send it and wait for the answer,
+ * for details on the implementation check 'get_cputime()'
+ * in the frsh_service_th.c source file
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT(*) (invalid vres or contract type)
+ * FRSH_ERR_NOT_CONTRACTED_VRES(*)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread) *
+ */
+int frsh_vres_get_usage(const frsh_vres_id_t vres, struct timespec *spent)
+{
+ frsh_in_msg_t vres_msg;
+ frsh_out_msg_t cputime_msg;
+
+#ifdef DEBUG
+ strncpy(FUNCNAME, "frsh_vres_get_usage", 20);
+#endif
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (spent == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't return in a NULL spent");
+ /* prepare the message */
+ vres_msg.type = FRSH_MT_GET_CPUTIME;
+ vres_msg.val.get_cputime.vres_id = vres;
+ /* contact the service thread for the usage retrieval */
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &vres_msg, &cputime_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ if (cputime_msg.error != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(cputime_msg.error,
+ "can't get the renegotiation status");
+ /* renegotiation_stratus pointer untouched if something has gone wrong */
+ *spent = cputime_msg.val.get_cputime.cputime;
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_vres_get_remaining_budget()
+ *
+ * Obtains from the service thread the actual remaining budget
+ * of a vres (independently by the contract type).
+ *
+ * As usual only prepares the message, send it and wait for the answer,
+ * for details on the implementation check 'get_current_budget()'
+ * in the frsh_service_th.c source file
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT(*) (invalid vres)
+ * FRSH_ERR_NOT_CONTRACTED_VRES(*)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread) *
+ */
+int frsh_vres_get_remaining_budget(const frsh_vres_id_t vres, struct timespec *budget)
+{
+ frsh_in_msg_t vres_msg;
+ frsh_out_msg_t budget_msg;
+
+#ifdef DEBUG
+ strncpy(FUNCNAME, "frsh_vres_get_remaining_budget", 31);
+#endif
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (budget == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't return in a NULL budget");
+ /* prepare the message */
+ vres_msg.type = FRSH_MT_GET_CURRENTBUDGET;
+ vres_msg.val.get_currentbudget.vres_id = vres;
+ /* contact the service thread for the usage retrieval */
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &vres_msg, &budget_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ if (budget_msg.error != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(budget_msg.error,
+ "can't get the remaining budget");
+ /* budget pointer untouched if something has gone wrong */
+ *budget = budget_msg.val.get_currentbudget.currentbudget;
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_vres_get_budget_and_period()
+ *
+ * Obtains from the service thread the actual budget and period contracted
+ * for a vres (independently by the contract type).
+ *
+ * As usual only prepares the message, send it and wait for the answer,
+ * for details on the implementation check 'get_budget_and_period()'
+ * in the frsh_service_th.c source file
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT(*) (invalid vres)
+ * FRSH_ERR_NOT_CONTRACTED_VRES(*)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread)
+ */
+int frsh_vres_get_budget_and_period(const frsh_vres_id_t vres,
+ struct timespec *budget,
+ struct timespec *period)
+{
+ frsh_in_msg_t vres_msg;
+ frsh_out_msg_t params_msg;
+
+#ifdef DEBUG
+ strncpy(FUNCNAME, "frsh_vres_get_budget_and_period", 33);
+#endif
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (budget == NULL || period == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't return in a NULL budget or period");
+ /* prepare the message */
+ vres_msg.type = FRSH_MT_GET_BUDGET_AND_PERIOD;
+ vres_msg.val.get_budget_and_period.vres_id = vres;
+ /* contact the service thread for the usage retrieval */
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &vres_msg, ¶ms_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ if (params_msg.error != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(params_msg.error,
+ "can't get budget and period");
+ /* budget and period pointers untouched if something has gone wrong */
+ *budget = params_msg.val.get_budget_and_period.budget;
+ *period = params_msg.val.get_budget_and_period.period;
+
+ return FRSH_NO_ERROR;
+}
+
+/////////////////////////////////////////////
+// S E R V I C E T H R E A D T U N I N G
+/////////////////////////////////////////////
+
+/*
+ * frsh_service_thread_set_data(), adapt timing guarantees for the service thread
+ *
+ * Modifies the execution period and budget of the service thread from the
+ * defaults configured for it and negotiated during service thread
+ * initialization.
+ *
+ * Here we only request the operation sending a message to the service thread
+ * itself (and waiting for the answer), check the service thread main code
+ * in the frsh_service_th.c source file for the implementation details.
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT (NULL or inconsistent budget or period)
+ * FRSH_ERR_CONTRACT_REJECTED(*)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread) *
+ */
+int frsh_service_thread_set_data(const struct timespec *budget,
+ const struct timespec *period,
+ bool *accepted)
+{
+ frsh_in_msg_t params_msg;
+ frsh_out_msg_t ack_msg;
+
+#ifdef DEBUG
+ strncpy(FUNCNAME, "frsh_service_thread_set_data", 29);
+#endif
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (budget == NULL || period == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't setup a NULL budget or period");
+ if (frsh_rel_time_smaller(*period, *budget))
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't setup a budget greather than the period");
+ /* prepare the message */
+ params_msg.type = FRSH_MT_SET_SERVICE_THREAD_DATA;
+ params_msg.val.set_service_thread_data.budget = *budget;
+ params_msg.val.set_service_thread_data.period = *period;
+ /* contact the service thread for the usage retrieval */
+ if (frsh_service_th_ask_for(frsh_service_th_pid, ¶ms_msg, &ack_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ if (ack_msg.error != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(ack_msg.error,
+ "can't setup service thread budget and period");
+ *accepted = ack_msg.val.set_service_thread_data.accepted;
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_service_thread_get_data(), obtain timing guarantees for the service thread
+ *
+ * Obtains the actual execution period and budget of the service.
+ *
+ * Here we only request the operation sending a message to the service thread
+ * itself (and waiting for the answer), check the service thread main code
+ * in the frsh_service_th.c source file for the implementation details.
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT (NULL budget or period)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY (error in communication with the service thread) *
+ */
+int frsh_service_thread_get_data(frsh_rel_time_t *budget, frsh_rel_time_t *period)
+{
+ frsh_in_msg_t request_msg;
+ frsh_out_msg_t params_msg;
+
+#ifdef DEBUG
+ strncpy(FUNCNAME, "frsh_service_thread_get_data", 29);
+#endif
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (budget == NULL || period == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't return results in a NULL budget or period");
+ /* prepare the message */
+ request_msg.type = FRSH_MT_GET_SERVICE_THREAD_DATA;
+ /* contact the service thread for the usage retrieval */
+ if (frsh_service_th_ask_for(frsh_service_th_pid, &request_msg, ¶ms_msg) != FRSH_SERVICE_TH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SCHEDULER_REPLY,
+ "can't receive correct answer from the service thread");
+ if (params_msg.error != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(params_msg.error,
+ "can't obtain current service thread budget and period");
+ /* budget and period pointers untouched if something has gone wrong */
+ *budget = params_msg.val.get_budget_and_period.budget;
+ *period = params_msg.val.get_budget_and_period.period;
+
+ return FRSH_NO_ERROR;
+}
+
+
--- /dev/null
+
+//synchobj_repo_t synchobj_repo; /* defined downward, after the type definition! */
+
+/*
+ * synchronization objects repository
+ *
+ * data structure and macro declaration for the handling of the repository
+ * of synchronization objects needed by the API implementation.
+ * It's used only in the core API module so no problem implementing it all
+ * in this file without affecting the header files in frsh/include with
+ * such an implementation specific and tighted issue
+ *
+ * Note that mutual exclusive access is implemented both for the repository
+ * as a whole and for each single element to maximize the achievable
+ * parallelism and concurrency execution of threads
+ *
+ * Note also the synchronization object (subsection of the core) API is
+ * implemented within this file, without any request to the service thread,
+ * and so all "remain" local to a single process!
+ */
+
+/* data structures */
+
+typedef struct synchobj_repo_entry {
+ frsh_mutex_t mutex;
+ fosa_cond_t sync;
+ int events;
+ int queued;
+} synchobj_repo_entry_t;
+
+typedef struct synchobj_repo {
+ synchobj_repo_entry_t repo[FRSH_MAX_N_SYNCH_OBJECTS];
+ int synchobj_number;
+ frsh_mutex_t mutex;
+} synchobj_repo_t;
+
+synchobj_repo_t synchobj_repo; /* global variable */
+
+/* macro and functions */
+
+/*
+ * access functions to the repository
+ *
+ * some simple macro which help keep synchobj_repo_t opaque
+ * for the sake of code cleanness
+ */
+
+/* given the handle of a synchronization object returns its index into the
+ * repository (frsh_synchobj_handle_t remains opaque) */
+#define synchobj_handle_2_ind(h) \
+ ( h )
+/* given the index of a synchronization object in the repository returns
+ * an handle to it (frsh_synchobj_handle_t remains opaque)*/
+#define synchobj_ind_2_handle(i) \
+ ( i )
+/* given a handle of a synchronization object returns a pointer to
+ * its entry into the repository */
+#define get_synchobj_entry(handle) \
+( & ( synchobj_repo.repo[synchobj_handle_2_ind(handle)] ) )
+/* return a pointer to the synchronization object repository mutex */
+#define get_synchobj_repo_mutex() \
+ ( & ( synchobj_repo.mutex ) )
+/* gives the actual number of synchronization objects in the repository */
+#define get_synchobj_number() \
+ ( synchobj_repo.synchobj_number )
+
+/*
+ * consistency and status checks
+ *
+ * common used checkings and tests about the access to the repository
+ * and the status of each entry
+ */
+
+/* are we accessing the repository with a valid index value ? */
+#define check_synchobj_repo_ind(ind) \
+ ( ( ind >= 0 && ind < FRSH_MAX_N_SYNCH_OBJECTS ) ? true: false )
+/* is the repository entry (correctly accessed and) free ? */
+#define check_synchobj_repo_entry_free(ind) \
+ ( ( (check_synchobj_repo_ind(ind)) && \
+ synchobj_repo.repo[ind].events == -1 ) ? true : false )
+/* is the repository entry (correctly accessed and) non free ? */
+#define check_synchobj_repo_entry_nonfree(ind) \
+ ( ( (check_synchobj_repo_ind(ind)) && \
+ synchobj_repo.repo[ind].events != -1 ) ? true : false )
+
+/*
+ * initialize the repository
+ *
+ * sets all entries to invalid (that is, free) and init
+ * the "global" mutexe
+ *
+ * possible return values:
+ * true (all ok)
+ * false (something wrong with the mutex)
+ */
+static inline bool synchobj_repo_init()
+{
+ int i;
+
+ if (fosa_mutex_init(&synchobj_repo.mutex, 0) != 0)
+ return false;
+
+ synchobj_repo.synchobj_number = 0;
+ for (i = 0; i < FRSH_MAX_N_SYNCH_OBJECTS; i++) {
+ synchobj_repo.repo[i].events = -1;
+ synchobj_repo.repo[i].queued = -1;
+ }
+
+ return true;
+}
+
+/*
+ * add an entry
+ *
+ * adds an entry into the repository. If successful the index of the entry is
+ * returned in vres_ind.
+ *
+ * We suppose the caller where to place the new entry and "suggests" us a
+ * free repository entry in synchobj_ind. We then check if it's really free
+ * and, if yes, we add the entry right there.
+ * If, on the other way, the entry is not free we need to search the whole
+ * repository for a suitable place.
+ *
+ * possible return values:
+ * true (entry correctly added)
+ * false (entry not added, maybe no more room in the repository!)
+ */
+static inline bool synchobj_repo_put(int *synchobj_ind)
+{
+
+ int i;
+ bool result;
+
+ /* lock the repository */
+ fosa_mutex_lock(&synchobj_repo.mutex);
+ /* try to place the new entry in the caller provided position (if any)
+ * and, only if it's not free, scan all the repository for
+ * a different and suitable place */
+ if (synchobj_ind != NULL &&
+ check_synchobj_repo_entry_free(*synchobj_ind % FRSH_MAX_N_SYNCH_OBJECTS))
+ i = *synchobj_ind % FRSH_MAX_N_SYNCH_OBJECTS;
+ else {
+ i = 0;
+ while (i < FRSH_MAX_N_SYNCH_OBJECTS && !check_synchobj_repo_entry_free(i))
+ i++;
+ }
+ /* if we're sure it's valid and free we place the
+ * thread entry into the repository in position 'i' */
+ result = false;
+ if (check_synchobj_repo_entry_free(i)) {
+ if (fosa_mutex_init(&synchobj_repo.repo[i].mutex, 0) != 0)
+ return false;
+ if (fosa_cond_init(&synchobj_repo.repo[i].sync) != 0)
+ return false;
+ synchobj_repo.repo[i].events = 0;
+ synchobj_repo.repo[i].queued = 0;
+ if (synchobj_ind != NULL)
+ *synchobj_ind = i;
+ result = true;
+ }
+
+ /* unlock the repository */
+ fosa_mutex_unlock(&synchobj_repo.mutex);
+
+ return result;
+}
+
+/*
+ * remove an entry
+ *
+ * sets the entry as free (if it already is not) and decrement the counter
+ *
+ * possible return values:
+ * true (all ok, entry was non-free and is now free)
+ * false (something wrong, entry was already free or index is out of renge)
+ */
+static inline bool synchobj_repo_free(const int synchobj_ind)
+{
+ bool result;
+
+ /* lock the whole repository */
+ fosa_mutex_lock(&synchobj_repo.mutex);
+
+ result = false;
+ if (check_synchobj_repo_entry_nonfree(synchobj_ind)) {
+ fosa_mutex_destroy(&synchobj_repo.repo[synchobj_ind].mutex);
+ fosa_cond_destroy(&synchobj_repo.repo[synchobj_ind].sync);
+ synchobj_repo.repo[synchobj_ind].events = -1;
+ synchobj_repo.repo[synchobj_ind].queued = -1;
+ synchobj_repo.synchobj_number--;
+ result = true;
+ }
+
+ /* unlock the whole repository */
+ fosa_mutex_unlock(&synchobj_repo.mutex);
+
+ return result;
+}
+
+/*
+ * is an entry free ?
+ *
+ * check if a specific entry of the repository can be considered free
+ * (we need do it with an atomic lock)
+ *
+ * possible return values:
+ * true (entry is free)
+ * false (entry is not free or index is out of range)
+ */
+static inline bool synchobj_repo_isfree(const int synchobj_ind)
+{
+ bool result;
+
+ /* lock the repository */
+ fosa_mutex_lock(&synchobj_repo.mutex);
+
+ result = check_synchobj_repo_entry_free(synchobj_ind);
+
+ /* unlock the repository */
+ fosa_mutex_unlock(&synchobj_repo.mutex);
+
+ return result;
+}
+
+/////////////////////////////////////////////////
+// S Y N C H R O N I Z A T I O N O B J E C T S
+/////////////////////////////////////////////////
+
+/*
+ * This section is implemented much differently from how it's described
+ * in the docs since the synchronization object are not unusable from
+ * INDETERMINATE workload type thread (remember we actually we're
+ * only handling such a type of vres!!), but they simply provide, for them,
+ * a conditional [timed] wait/signal mechanism as available and implemented in
+ * many OSs and threading library.
+ *
+ * In INDETERMINATE workloads, of course, a wait request on an synchronization
+ * object (or a timed wait request) does not imply the end of the current job
+ * nor cause any budget to be "returned", since no jobs are defined for them.
+ *
+ * In BUONDED workloads, when they'll be implemented here, we can flawlessy
+ * realize the API docs' semantic and consider end-job signals and budget
+ * return
+ *
+ * Note that, beside the peculiarity of this implementation being the
+ * orthogonality with respect to threads and processes, all the
+ * synchronization objects API section is implemented without bothering the
+ * service thread, so it remains local to the single process and usable from
+ * its various threads to synchronize themself, i.e. it is by no way usable in
+ * order to synchronize different processes or different threads among
+ * different processes between each other!
+ */
+
+/*
+ * frsh_synchobj_create(), create a synchronization object
+ *
+ * Note FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD and
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY are never returned as errors within
+ * this implementation
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT (NULL synchronization object handle)
+ * FRSH_ERR_TOO_MANY_SYNCH_OBJECTS
+ * FRSH_ERR_INTERNAL_ERROR (something, different from previous, went wrong)
+ */
+int frsh_synchobj_create(frsh_synchobj_handle_t *synch_handle)
+{
+ int synch_ind;
+
+#ifdef DEBUG
+ strncpy(FUNCNAME, "frsh_synchobj_create", 21);
+#endif
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (synch_handle == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't return a synchronization object in a NULL synch_handle");
+
+ /* add the object and return an handler to it */
+ if (synchobj_repo_put(&synch_ind))
+ *synch_handle = synchobj_ind_2_handle(synch_ind);
+ else
+ /* something wrong, try to guess what */
+ if (get_synchobj_number() >= FRSH_MAX_N_SYNCH_OBJECTS)
+ /* synchronization object max number reached */
+ PERROR_AND_RETURN(FRSH_ERR_TOO_MANY_SYNCH_OBJS,
+ "can't create any more synchronization objects");
+ else
+ /* unspecified error (this should almost never be reached) */
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't create the synchronization objects");
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_synchobj_destroy(), destroy a synchronization object
+ *
+ * Note we check if wakeing up some threads is needed and we do this while
+ * holding a lock on the synchronization object, acquired while holding
+ * a lock on the whole repository in order to prevent races
+ *
+ * Note FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD and
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY are never returned as errors within
+ * this implementation too
+ *
+ * possible return value:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_INVALID_SYNCH_OBJ_HANDLE
+ * FRSH_ERR_INTERNAL_ERROR (something, different from previous, went wrong)
+ */
+int frsh_synchobj_destroy(const frsh_synchobj_handle_t synch_handle)
+{
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (synchobj_repo_isfree(synchobj_handle_2_ind(synch_handle)))
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SYNCH_OBJ_HANDLE,
+ "can't destroy a synchronization object from an invalid synch_handle");
+
+ /* get an exclusive access lock to the synchronization object
+ * while holding the exclusive access to the whole repository for the
+ * sake of safetyness */
+ fosa_mutex_lock(get_synchobj_repo_mutex());
+ fosa_mutex_lock(&(get_synchobj_entry(synch_handle)->mutex));
+ fosa_mutex_unlock(get_synchobj_repo_mutex());
+ /* have I got to wake up someone ?? */
+ while (get_synchobj_entry(synch_handle)->queued > 0) {
+ if (fosa_cond_signal(&(get_synchobj_entry(synch_handle)->sync)) != 0) {
+ fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
+ fosa_mutex_unlock(get_synchobj_repo_mutex());
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't wake up blocked threads while destroying the synchronization object");
+ } else
+ get_synchobj_entry(synch_handle)->queued--;
+ }
+ /* release the lock on the synchronization object */
+ fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
+
+ /* remove the synchronization object from the repository */
+ if (!synchobj_repo_free(synchobj_handle_2_ind(synch_handle)))
+ /* unspecified error (this should almost never be reached) */
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't delete the synchronization objects");
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_synchobj_wait() and frsh_synchobj_wit_with_timeout
+ *
+ * They're very very much similar between each other so we choose to implement
+ * them using a single generic function with a few more parameters to
+ * discriminate the two behaviours, avoiding a lot of code replication
+ */
+
+static int synchobj_wait(bool with_timeoout, /* forward declaration of the generic wait function */
+ const frsh_synchobj_handle_t synch_handle,
+ const struct timespec *abs_timeout,
+ bool *timed_out,
+ struct timespec *next_budget,
+ struct timespec *next_period,
+ bool *was_deadline_missed,
+ bool *was_budget_overran);
+
+/*
+ * frsh_synchobj_wait(), stop the thread till signaled by another one
+ *
+ * Implements the standard behaviour of a wait for a condition to be verified
+ * and signaled by another thread of the process.
+ *
+ * As stated before is perfectly usable even by the INDETERMINATE workloads
+ * for whom it does not represent the 'end job' event.
+ *
+ * It's implemented simply by a call to the generic function coded below
+ *
+ * Note FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD and
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY are never returned as errors within
+ * this implementation and also FRSH_ERR_WORKLOAD_NOT_COMPATIBLE
+ * is ignored by us
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_INVALID_SYNCH_OBJ_HANDLE (invalid synch. object or too many thread queued on it)
+ * all that frsh_thread_get_vres_id returns (FRSH_ERR_NOT_BOUND, )
+ * FRSH_ERR_INTERNAL_ERROR (something wrong trying to wait on the object)
+ */
+int frsh_synchobj_wait(const frsh_synchobj_handle_t synch_handle,
+ frsh_rel_time_t *next_budget,
+ frsh_rel_time_t *next_period,
+ bool *was_deadline_missed,
+ bool *was_budget_overran)
+{
+ /* simply call the generic function asking for a wait without any timeout */
+ return synchobj_wait(false, synch_handle, NULL, NULL, next_budget, next_period,
+ was_deadline_missed, was_budget_overran);
+}
+
+/*
+ * frsh_synchobj_wait_with_timeout(), stop the thread till a timeout or a signal by another one
+ *
+ * Implements the standard behaviour of a wait for a condition to be verified
+ * and signaled by another thread of the process with a max. timeout value
+ *
+ * It's exactly the same as 'frsh_synchobj_wait()' with the only difference of
+ * the timeout and so it's, again, implemented simply by a call to the generic
+ * function with the correct parameters
+ *
+ * Note FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD and
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY are never returned as errors within
+ * this implementation and also FRSH_ERR_WORKLOAD_NOT_COMPATIBLE
+ * is ignored by us
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_INVALID_SYNCH_OBJ_HANDLE (invalid synch. object or too many thread queued on it)
+ * all that 'frsh_thread_get_vres_id()' returns (FRSH_ERR_NOT_BOUND, )
+ * FRSH_ERR_INTERNAL_ERROR (something wrong trying to wait on the object)
+ */
+int frsh_synchobj_wait_with_timeout(
+ const frsh_synchobj_handle_t synch_handle,
+ const frsh_abs_time_t *abs_timeout,
+ bool *timed_out,
+ frsh_rel_time_t *next_budget,
+ frsh_rel_time_t *next_period,
+ bool *was_deadline_missed,
+ bool *was_budget_overran)
+{
+ /* simply call the generic function asking for a wait with the specified timeout */
+ return synchobj_wait(true, synch_handle, abs_timeout, timed_out, next_budget, next_period,
+ was_deadline_missed, was_budget_overran);
+}
+
+/*
+ * generic function definition:
+ * it _really_ implements both (depending on the parameters)
+ * wait on synchronization objects API calls
+ */
+static int synchobj_wait(bool with_timeout, /* discriminating parameter between the two functions */
+ const frsh_synchobj_handle_t synch_handle,
+ const struct timespec *abs_timeout,
+ bool *timed_out,
+ struct timespec *next_budget,
+ struct timespec *next_period,
+ bool *was_deadline_missed,
+ bool *was_budget_overran)
+{
+ frsh_thread_id_t thread_self;
+ qres_sid_t thread_sid;
+ qres_time_t qres_thread_budget;
+ struct timespec tmp_thread_budget, tmp_thread_period;
+ frsh_vres_id_t vres_id;
+ int frsh_status, timedwait_status;
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ /* check the thread is running with a negotiated contract */
+ thread_self = fosa_thread_self();
+ thread_sid = FRSH_QRES_NOT_VALID_SID;
+ vres_id = FRSH_NOT_VALID_VRES_ID;
+ /* ask AQuoSA directly, if it's succesfull we can avoid a call to
+ * the service thread that is much less overhead!! */
+ if (qres_get_sid(thread_self.linux_pid, thread_self.linux_tid, &thread_sid) == QOS_E_NOSERVER)
+ /* maybe we're bounded to a background vres and, in order
+ * of being sure, we need to ask the service thread :-( */
+ if ( (frsh_status = frsh_thread_get_vres_id(thread_self, &vres_id)) != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(frsh_status,
+ "can't wait if the thread is not bound to any vres");
+ if (synchobj_repo_isfree(synchobj_handle_2_ind(synch_handle)))
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SYNCH_OBJ_HANDLE,
+ "can't wait on an synchronization object via an invalid synch_handler");
+
+ /* acquire the exclusive access lock on the synchronization object
+ * while holding it on the whole repository */
+ fosa_mutex_lock(get_synchobj_repo_mutex());
+ fosa_mutex_lock(&(get_synchobj_entry(synch_handle)->mutex));
+ fosa_mutex_unlock(get_synchobj_repo_mutex());
+
+ /* check if we can wait on the object or the limit has already been reached */
+ if ((get_synchobj_entry(synch_handle)->events == 0) &&
+ (get_synchobj_entry(synch_handle)->queued >= FRSH_MAX_N_VRES_IN_SYNCH_OBJECT)) {
+ fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SYNCH_OBJ_HANDLE,
+ "can't queue more vres on this synchronization object");
+ }
+ /* we need to wait only if there are no ready events */
+ if (!get_synchobj_entry(synch_handle)->events) {
+ /* inform we're going to suspend oursef! */
+ get_synchobj_entry(synch_handle)->queued++;
+ if (with_timeout) {
+ *timed_out = false;
+ timedwait_status = fosa_cond_timedwait(&(get_synchobj_entry(synch_handle)->sync),
+ &(get_synchobj_entry(synch_handle)->mutex),
+ abs_timeout);
+ if (timedwait_status != 0) {
+ if (timedwait_status == ETIMEDOUT) {
+ /* no signal event before the timeout */
+ *timed_out = true;
+ get_synchobj_entry(synch_handle)->events++; /* preventive increment */
+ } else {
+ /* some other strange error! */
+ fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't wait on the synchronization object");
+ }
+ }
+ } else
+ if (fosa_cond_wait(&(get_synchobj_entry(synch_handle)->sync),
+ &(get_synchobj_entry(synch_handle)->mutex)) != 0) {
+ fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't wait on the syncrhonization object");
+ }
+ /* the synchronization object is still valid? */
+ if (synchobj_repo_isfree(synchobj_handle_2_ind(synch_handle)))
+ /* no, someone destroyed our synchronization object! */
+ PERROR_AND_RETURN(FRSH_ERR_INVALID_SYNCH_OBJ_HANDLE,
+ "synchronization object no longer valid, it has been destroyed during wait");
+ get_synchobj_entry(synch_handle)->queued--;
+ }
+ get_synchobj_entry(synch_handle)->events--;
+ /* all done, release the lock on the synchronization object */
+ fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
+
+ /* now retreive timing (budget and period) parameters, don't care about
+ * overruns (remember we're always WT_INDETERMINATE) and make them
+ * both 'false' */
+ if (next_period != NULL || (next_budget != NULL && thread_sid == -1)) {
+ /* ask the service thread only if it's strictly necessary !! */
+ if (vres_id == FRSH_NOT_VALID_VRES_ID)
+ /* we need to know (from the service thread) the vres_id */
+ if ( (frsh_status = frsh_thread_get_vres_id(thread_self, &vres_id)) != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(frsh_status,
+ "can't gather vres info for period and budget retrieval");
+ if (frsh_vres_get_budget_and_period(vres_id,
+ &tmp_thread_budget,
+ &tmp_thread_period) != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't get vres/contract budget and period");
+ }
+ if (next_budget != NULL) {
+ if (thread_sid == FRSH_QRES_NOT_VALID_SID)
+ /* background thread, we use the contracted budget
+ * retrieved previously */
+ *next_budget = tmp_thread_budget;
+ else {
+ /* regular thread, ask for the actual budget direclty to AQuoSA
+ * (much less overhead !!) */
+ if (qres_get_curr_budget(thread_sid, &qres_thread_budget) != QOS_OK)
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't get the actual budget for the vres");
+ usec_to_timespec(*next_budget, qres_thread_budget);
+ }
+ }
+ if (next_period != NULL)
+ *next_period = tmp_thread_period;
+ if (was_deadline_missed != NULL)
+ was_deadline_missed = false;
+ if (was_budget_overran != NULL)
+ was_budget_overran = false;
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_synchobj_signal(), notify a synchronization object
+ *
+ * Remember if noone is waiting for the notification it is queued in the
+ * synchronization objects
+ *
+ * Note FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD and
+ * FRSH_ERR_INVALID_SCHEDULER_REPLY are never returned as errors within
+ * this implementation too
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT (invalid synch_handle)
+ * FRSH_ERR_TOO_MANY_EVENTS_IN_SYNCH_OBJ
+ */
+int frsh_synchobj_signal(const frsh_synchobj_handle_t synch_handle)
+{
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (synchobj_repo_isfree(synchobj_handle_2_ind(synch_handle)))
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't signal a synchronization object via an invalid synch_handle");
+ /* acquire the exclusive access lock on the synchronization object
+ * while holding it on the whole repository */
+ fosa_mutex_lock(get_synchobj_repo_mutex());
+ fosa_mutex_lock(&(get_synchobj_entry(synch_handle)->mutex));
+ fosa_mutex_unlock(get_synchobj_repo_mutex());
+
+ if (get_synchobj_entry(synch_handle)->events >= FRSH_MAX_N_EVENTS_IN_SYNCH_OBJECT) {
+ fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
+ PERROR_AND_RETURN(FRSH_ERR_TOO_MANY_EVENTS_IN_SYNCH_OBJ,
+ "can't enqueue more events on the synchronization object");
+ }
+ get_synchobj_entry(synch_handle)->events++;
+
+ /* release the lock */
+ fosa_mutex_unlock(&(get_synchobj_entry(synch_handle)->mutex));
+ /* and, finally, signal the condition */
+ fosa_cond_signal(&(get_synchobj_entry(synch_handle)->sync));
+
+ return FRSH_NO_ERROR;
+}
+
+/*
+ * frsh_timed_wait(), sleep until specified absolute time
+ *
+ * Again, it does not imply 'end job' or any budget modification for
+ * INDETERMINATE workload vres, simply wait for the timer to fire!
+ *
+ * The timeout is implemented via the 'clock_nanosleep()' function
+ * (we need to consider a fosa wrapper for it too) in order to get rid
+ * of all the problems related to signal handling in a multithreaded
+ * environment (and even because it's the simplest and best suited
+ * solution for the acheiving what we need to!!)
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT (NULL abs_time)
+ * FRSH_ERR_INTERNAL_ERROR (FRSH_ERR_TIME_SPEC_IN_THE_PAST)
+ * FRSH_ERR_INTERNAL_ERROR (something wrong with timer and/or signal handling)
+ * all that 'frsh_thread_get_vres_id()' returns (FRSH_ERR_NOT_BOUND, )
+ */
+
+int frsh_timed_wait (
+ const frsh_abs_time_t *abs_time,
+ frsh_rel_time_t *next_budget,
+ frsh_rel_time_t *next_period,
+ bool *was_deadline_missed,
+ bool *was_budget_overran)
+{
+ frsh_thread_id_t thread_self;
+ qres_sid_t thread_sid;
+ qres_time_t qres_thread_budget;
+ struct timespec tmp_thread_budget, tmp_thread_period;
+ frsh_vres_id_t vres_id;
+ frsh_abs_time_t actual_time, rm_time;
+ int frsh_status;
+
+ /* check for framework initialization and arguments */
+ if (!frsh_initialized)
+ PERROR_AND_RETURN(FRSH_ERR_NOT_INITIALIZED,
+ "can't proceed before initializing FRSH with 'frsh_init()'!");
+ if (abs_time == NULL)
+ PERROR_AND_RETURN(FRSH_ERR_BAD_ARGUMENT,
+ "can't wait for a NULL abs_time");
+ /* check the thread is running with a negotiated contract */
+ thread_self = fosa_thread_self();
+ thread_sid = FRSH_QRES_NOT_VALID_SID;
+ vres_id = FRSH_NOT_VALID_VRES_ID;
+ if (qres_get_sid(thread_self.linux_pid, thread_self.linux_tid, &thread_sid) == QOS_E_NOSERVER)
+ /* maybe we're bounded to a background vres and, in order
+ * of being sure, we need to ask the service thread :-( */
+ if ( (frsh_status = frsh_thread_get_vres_id(thread_self, &vres_id)) != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(frsh_status,
+ "can't get the vres id the calling thread is associated with");
+ /* check the provided absolute time reference is in the future */
+ if (fosa_clock_get_time(FOSA_CLOCK_REALTIME, &actual_time) < 0)
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't get the current time");
+ if (frsh_abs_time_smaller(*abs_time, actual_time))
+ //PERROR_AND_RETURN(FRSH_ERR_TIME_SPEC_IN_THE_PAST,
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't wait for a past absolute time");
+ /* put the thread to sleep for the requested interval */
+ if (clock_nanosleep(FOSA_CLOCK_REALTIME, TIMER_ABSTIME, abs_time, &rm_time) < 0)
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't put the thread to sleep");
+ /* if ( <check, via rm_time, if we've been interrupted> )
+ * ... ... ...
+ * ... ... ... */
+ /* retreive timing (budget and period) parameters, don't care about
+ * overruns (remember we're always WT_INDETERMINATE) and make them
+ * both 'false' */
+ if (next_period != NULL || (next_budget != NULL && thread_sid == FRSH_QRES_NOT_VALID_SID)) {
+ /* ask the service thread only if it's strictly necessary !! */
+ if (vres_id == FRSH_NOT_VALID_VRES_ID)
+ /* we need to know (from the service thread) the vres_id !! */
+ if ( (frsh_status = frsh_thread_get_vres_id(thread_self, &vres_id)) != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(frsh_status,
+ "can't gather vres info for period and budget retrieval");
+ if (frsh_vres_get_budget_and_period(vres_id,
+ &tmp_thread_budget,
+ &tmp_thread_period) != FRSH_NO_ERROR)
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't get vres/contract budget and period");
+ }
+ if (next_budget != NULL) {
+ if (thread_sid == FRSH_QRES_NOT_VALID_SID)
+ /* background thread, we use the contracted budget
+ * retrieved previously */
+ *next_budget = tmp_thread_budget;
+ else {
+ /* regular thread, ask for the actual budget direclty to AQuoSA
+ * (much less overhead !!) */
+ if (qres_get_curr_budget(thread_sid, &qres_thread_budget) != QOS_OK)
+ PERROR_AND_RETURN(FRSH_ERR_INTERNAL_ERROR,
+ "can't get the actual budget for the vres");
+ usec_to_timespec(*next_budget, qres_thread_budget);
+ }
+ }
+ if (next_period != NULL)
+ *next_period = tmp_thread_period;
+ if (was_deadline_missed != NULL)
+ *was_deadline_missed = false;
+ if (was_budget_overran != NULL)
+ *was_budget_overran = false;
+
+ return FRSH_NO_ERROR;
+}
+