]> rtime.felk.cvut.cz Git - frescor/frsh.git/commitdiff
Added cpu control group support to FRESCOR that provides cpu
authorMartin Molnar <molnam1@fel.cvut.cz>
Sun, 4 Jan 2009 22:44:36 +0000 (23:44 +0100)
committerMartin <molnam1@fel.cvut.cz>
Sun, 4 Jan 2009 22:44:36 +0000 (23:44 +0100)
vres on pure 2.6 linux for rt threads.

19 files changed:
frsh_api/Makefile.omk
frsh_api/frsh_core.c
resources/cpucg/Makefile [new file with mode: 0644]
resources/cpucg/Makefile.omk [new file with mode: 0644]
resources/cpucg/lib/Makefile [new file with mode: 0644]
resources/cpucg/lib/Makefile.omk [new file with mode: 0644]
resources/cpucg/lib/cpucg_contract.c [new file with mode: 0644]
resources/cpucg/lib/cpucg_contract.h [new file with mode: 0644]
resources/cpucg/lib/cpucg_fra.c [new file with mode: 0644]
resources/cpucg/lib/cpucg_res.h [new file with mode: 0644]
resources/cpucg/lib/frsh_cpucg.c [new file with mode: 0644]
resources/cpucg/lib/timespec_usec_ops.h [new file with mode: 0644]
resources/cpucg/mngr/Makefile [new file with mode: 0644]
resources/cpucg/mngr/Makefile.omk [new file with mode: 0644]
resources/cpucg/mngr/cpucg_mngr.c [new file with mode: 0644]
resources/cpucg/tests/Makefile [new file with mode: 0644]
resources/cpucg/tests/Makefile.omk [new file with mode: 0644]
resources/cpucg/tests/config.omk [new file with mode: 0644]
resources/cpucg/tests/cpucgtest.c [new file with mode: 0644]

index c14a2265c4cd15934de79d3947e8864a4cabd588..4f0c176438a767567c1484bad638e8d7a762fc90 100644 (file)
@@ -8,6 +8,7 @@ frsh_LIBS = fna fcb_client forb contract fra ulut fosa $(allocator-libs-y)
 config_include_HEADERS = frsh_resources.h
 frsh_resources_DEFINES = CONFIG_RESOURCE_DUMMY \
                         CONFIG_AQUOSA\
+                        CONFIG_CPUCG\
                         CONFIG_FWP \
                         CONFIG_RESOURCE_ITEM
 
@@ -15,3 +16,4 @@ allocator-libs-$(CONFIG_RESOURCE_DUMMY) += fra_dummy
 allocator-libs-$(CONFIG_RESOURCE_ITEM) += fra_item
 allocator-libs-$(CONFIG_FWP) += frsh_fwp fwp
 allocator-libs-$(CONFIG_AQUOSA) += frshaqcpu
+allocator-libs-$(CONFIG_CPUCG) += frshcpucg
index b771de390e0fa68b1fcd1b30d33af62da3a8efb9..1328f8ef8e9890da9b6f7a2289428363562a7cfe 100644 (file)
 #include <aqcpu_res.h>
 #endif
 
+#ifdef CONFIG_CPUCG
+#include <cpucg_res.h>
+#endif
+
 #ifdef CONFIG_RESOURCE_DUMMY
 #include <res_dummy.h>
 #endif
@@ -57,6 +61,10 @@ int frsh_init()
        ret = aqcpu_fra_init();
        if (ret) goto err;
 #endif
+#ifdef CONFIG_CPUCG
+       ret = cpucg_fra_init();
+       if (ret) goto err;
+#endif
 #ifdef CONFIG_RESOURCE_DUMMY
        ret = fra_dummy_init();
        if (ret) goto err;
diff --git a/resources/cpucg/Makefile b/resources/cpucg/Makefile
new file mode 100644 (file)
index 0000000..b22a357
--- /dev/null
@@ -0,0 +1,14 @@
+# Generic directory or leaf node makefile for OCERA make framework
+
+ifndef MAKERULES_DIR
+MAKERULES_DIR := $(shell ( old_pwd="" ;  while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd`  ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) )
+endif
+
+ifeq ($(MAKERULES_DIR),)
+all : default
+.DEFAULT::
+       @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n"
+else
+include $(MAKERULES_DIR)/Makefile.rules
+endif
+
diff --git a/resources/cpucg/Makefile.omk b/resources/cpucg/Makefile.omk
new file mode 100644 (file)
index 0000000..be146ba
--- /dev/null
@@ -0,0 +1,8 @@
+default_CONFIG = CONFIG_CPUCG=x
+
+ifeq ($(CONFIG_CPUCG),y)
+SUBDIRS = lib mngr tests 
+CFLAGS+= -Wall -Wextra -D_REENTRANT
+endif
+#include_HEADERS +=$(wildcard aquosa/qresmod/*.h)
+#include_HEADERS +=$(wildcard aquosa/rresmod/*.h)
diff --git a/resources/cpucg/lib/Makefile b/resources/cpucg/lib/Makefile
new file mode 100644 (file)
index 0000000..b22a357
--- /dev/null
@@ -0,0 +1,14 @@
+# Generic directory or leaf node makefile for OCERA make framework
+
+ifndef MAKERULES_DIR
+MAKERULES_DIR := $(shell ( old_pwd="" ;  while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd`  ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) )
+endif
+
+ifeq ($(MAKERULES_DIR),)
+all : default
+.DEFAULT::
+       @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n"
+else
+include $(MAKERULES_DIR)/Makefile.rules
+endif
+
diff --git a/resources/cpucg/lib/Makefile.omk b/resources/cpucg/lib/Makefile.omk
new file mode 100644 (file)
index 0000000..451dc02
--- /dev/null
@@ -0,0 +1,6 @@
+shared_LIBRARIES = frshcpucg
+frshcpucg_SOURCES += frsh_cpucg.c cpucg_contract.c cpucg_fra.c 
+include_HEADERS += cpucg_contract.h cpucg_res.h timespec_usec_ops.h
+frshcpucg_LIBS += cgroup  
+#include_HEADERS +=$(wildcard aquosa/qresmod/*.h)
+#include_HEADERS +=$(wildcard aquosa/rresmod/*.h)
diff --git a/resources/cpucg/lib/cpucg_contract.c b/resources/cpucg/lib/cpucg_contract.c
new file mode 100644 (file)
index 0000000..bd34ddb
--- /dev/null
@@ -0,0 +1,18 @@
+#include "cpucg_contract.h"
+
+int get_cpucg_params(fres_vres_t *vres, cpucg_params_t *params)
+{
+       fres_block_basic *basic;
+               
+       /* get params from contract */
+       basic = fres_contract_get_basic(vres->new);
+       
+       /* core contract parameters */
+       params->P = timespec_to_usec(basic->period);
+       /* non-core contract parameters */
+       /* right now, the same as minimum budget */
+       params->Q = timespec_to_usec(basic->budget);
+
+       return 0;
+}
+
diff --git a/resources/cpucg/lib/cpucg_contract.h b/resources/cpucg/lib/cpucg_contract.h
new file mode 100644 (file)
index 0000000..92f39e0
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef CPUCG_CONTRACT_H
+#include "timespec_usec_ops.h"
+#include <fra_generic.h>
+
+typedef 
+struct cpucg_params_t {
+       long long P;
+       long long Q;
+} cpucg_params_t;
+
+int get_cpucg_params(fres_vres_t *vres, cpucg_params_t *params);
+
+#endif /* CPUCG_CONTRACT_H */
diff --git a/resources/cpucg/lib/cpucg_fra.c b/resources/cpucg/lib/cpucg_fra.c
new file mode 100644 (file)
index 0000000..80bb14f
--- /dev/null
@@ -0,0 +1,235 @@
+/**************************************************************************/
+/* ---------------------------------------------------------------------- */
+/* Copyright (C) 2006 - 2008 FRESCOR consortium partners:                */
+/*                                                                       */
+/*   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 for a link to partners' websites         */
+/*                                                                       */
+/*          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.                                              */
+/*                                                                       */
+/*                                                                       */
+/*  This file is part of FRESCOR CPUCG (cpu control group)               */
+/*                                                                       */
+/* FWP is free software; you can redistribute it and/or modify it        */
+/* under terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2, or (at your option) any   */
+/* later version.  FWP 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 along with FWP; see file       */
+/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,  */
+/* Cambridge, MA 02139, USA.                                             */
+/*                                                                       */
+/* As a special exception, including AQCPU header files in a file,       */
+/* instantiating FWP generics or templates, or linking other files       */
+/* with FWP objects to produce an executable application, does not       */
+/* by itself cause the resulting executable application to be covered    */
+/* 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 Public License.                                    */
+/**************************************************************************/
+#include <ul_log.h>
+#include <fra_generic.h>
+
+#include "cpucg_contract.h"
+#include <stdio.h>
+#include <libcgroup.h>
+
+UL_LOG_CUST(ulogd_fra_cpucg);
+//ul_log_domain_t ulogd_fra_cpucg = {UL_LOGL_MSG, "fra_cpucg"};
+
+static int cpucg_initialized = 0; /* initialization flag */
+
+#define CGNAME 20
+/* 
+ * Permissions
+ */
+static uid_t tuid = 0;
+static gid_t tgid = 0;
+static uid_t cuid = 0;
+static gid_t cgid = 0;
+
+static int vres_inc = 0;
+
+/*
+ * Test whether Aquosa Cpu modue is initialized 
+ */
+static inline int cpucg_is_initialized()
+{
+       return (cpucg_initialized == 1);
+}
+
+static inline char* cpucg_get_name(void)
+{
+       char* cgname = malloc(CGNAME);
+       snprintf(cgname, CGNAME, "%d", getpid() + vres_inc++);
+       
+       return cgname; 
+}
+
+static int cpucg_create_vres(fres_vres_t *vres, void *priv)
+{
+       cpucg_params_t cpu_params;
+       struct cgroup_controller *cpucntl;
+       struct cgroup* ccg;
+       long int period;
+       long int budget;
+       char* cgroup_name;
+       int ret;
+
+       /* get aqcpu params from contract */
+       get_cpucg_params(vres, &cpu_params);
+       period = cpu_params.P;
+       budget = cpu_params.Q;
+       
+       /* create cpu vres */
+       cgroup_name = cpucg_get_name();
+       ccg = cgroup_new_cgroup(cgroup_name);
+       cgroup_set_uid_gid(ccg, tuid, tgid, cuid, cgid);
+       cpucntl = cgroup_add_controller(ccg, "cpu");
+       printf("To be Created CGCPU VRES(period=%ld us, budget=%ld us)\n",
+                       period, budget);
+       cgroup_add_value_uint64(cpucntl, "cpu.rt_period_us", period);
+       cgroup_add_value_uint64(cpucntl, "cpu.rt_runtime_us", budget);
+       
+       if ((ret = cgroup_create_cgroup(ccg, 1))) {
+               return ret;
+       }
+       
+       printf("Created CGCPU VRES(period=%lld us, budget=%lld us)\n",
+                       period, budget);
+       vres->priv = ccg;
+       
+       return 0;
+}
+
+/*
+ * aqcpu_cancel_vres(), cancels vres 
+ *
+ * The thread bound to the vres are unbound, and so, detached from their
+ * AQuoSA resource reservation servers and continue their execution according
+ * to the standard Linux scheduler policies.
+ *
+ */
+static int cpucg_cancel_vres(fres_vres_t *vres, void *priv)
+{
+       struct cgroup *cgroup;
+
+       if (vres->priv) {
+               errno = -EINVAL;
+               return -1;
+       }
+       
+       cgroup = (struct cgroup*) vres->priv;
+       /* TODO: Solve migration 
+       cgroup_delete_cgroup(cgroup, 1);*/
+       printf("Canceled CGCPU VRES\n");
+       cgroup_free(&cgroup);   
+       
+       return 0;
+}
+
+/* aqcpu_vres_change(), change some parameters of a vres
+ *
+ * In fact, since that AQuoSA call doesn't deal with _its_ Q_min (budget_min
+ * for in FRSH semantic) parameter all the renegotiation will be accepted but
+ * the new temporal behaviour is not guaranteed!
+ * Obviously this is a bug and should/will be corrected in AQuoSA as soon as
+ * possible.
+ *
+ */
+int cpucg_change_vres(fres_vres_t *vres, void *priv)
+{
+       struct cgroup *cgroup;
+       cpucg_params_t cpu_params;
+       
+       if (vres->priv) {
+               errno = -EINVAL;
+               return -1;
+       }
+       
+       cgroup = (struct cgroup*) vres->priv;
+       
+       /* get aqcpu params from contract */
+       get_cpucg_params(vres, &cpu_params);
+
+       /* TODO:
+        * cgroup->controller[0]->values[0]->value = cpu_params.P;      
+       cgroup->controller[0]->values[1]->value = cpu_params.Q; */
+       
+       ul_logmsg("AQCPU VRES params changed(period=%lld us,"
+                       "budget=%lld us)\n", cpu_params.P, cpu_params.Q);
+
+       return 0;
+}
+
+static struct fres_allocator cpucg_allocator = {
+       .res_type = FRSH_RT_PROCESSOR,
+       .res_id = 0,  /* CPU ID 0 */
+       .create_vres = cpucg_create_vres,
+       .cancel_vres = cpucg_cancel_vres,
+       .change_vres = cpucg_change_vres,
+       .priv = NULL
+};
+
+/*
+ * cpucg_fra_init()
+ *
+ * initialize FRSH for the calling process
+ *
+ * Must be called before starting using the framework.
+ * No FRSH call will be successful if this routine is not invoked
+ *
+ * Note that no BACKGROUND is created and negotiated and the caller thread
+ * is bound to no BACKGROUND vres, since no way is provided in order of
+ * specifying the contract label and get back the vres id!
+ *
+ * Note also that, since in this implementation the threads/processes with
+ * backgound contracts are left into the default Linux scheduler hands' and
+ * not attached to any AQuoSA server, while we're violating what D-AC2v1
+ * (pag. 14) says, we achieve exactly the same behaviour!!
+ *
+ * possible return values:
+ *  FRSH_NO_ERROR
+ *  FRSH_ERR_ALREADY_INITIALIZED
+ *  FRSH_ERR_INTERNAL_ERROR (something, different from the previous case, gone wrong)
+ */
+int cpucg_fra_init(void)
+{
+       if (cpucg_is_initialized()) {
+               return -1;
+       }
+
+       /* TODO: tets whether cpu controller is mounted */
+       //if (cgroup_init() || !cgroup_test_subsys_mounted("cpu")) {
+       if (cgroup_init()) {
+               return -1;
+       }
+
+       if (fra_register(&cpucg_allocator)) {
+               return -1;
+       }
+       
+       cpucg_initialized = 1;
+       return 0;
+}
+
+int cpucg_fra_exit()
+{
+       return 0;
+}
diff --git a/resources/cpucg/lib/cpucg_res.h b/resources/cpucg/lib/cpucg_res.h
new file mode 100644 (file)
index 0000000..40cc0c6
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef CPUCG_RES_H
+#define CPUCG_RES_H
+
+#include <forb.h>
+#include <fcb.h>
+#include <frsh_core.h>
+
+int cpucg_fra_init(void);
+
+#endif /* CPUCG_RES_H */
+
diff --git a/resources/cpucg/lib/frsh_cpucg.c b/resources/cpucg/lib/frsh_cpucg.c
new file mode 100644 (file)
index 0000000..10c089c
--- /dev/null
@@ -0,0 +1,439 @@
+// -----------------------------------------------------------------------
+//  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_aqcpu.c
+ *
+ * This file contains the implementation of FRSH API core functions on top
+ * of the AQuoSA framework, on GNU/Linux platform.
+ *
+ */
+
+/* Linux files */
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#define __USE_UNIX98
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <string.h>
+
+/* FRSH files */
+#include <frsh_cpp_macros.h>
+#include <fosa.h>
+#include <frsh_core_types.h>
+#include <frsh_error.h>
+
+#include <fres_vres.h>
+#include <libcgroup.h>
+
+/* local timepsec <-> usec utility macros */
+#include "timespec_usec_ops.h"
+
+
+/**
+ * structure used to pass the new created thread (or better its wrapper) the
+ * arguments it needs to bind itself to the vres.
+ */
+typedef struct {
+       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;*/
+
+/**
+ * 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)
+{
+       struct cgroup* cgroup = (struct cgroup*)vres->priv;
+       struct sched_param param;
+
+       /*if (!aqcpu_is_initialized) {
+                 return(FRSH_ERR_NOT_INITIALIZED);
+       }*/
+       
+
+       if (cgroup_attach_task_pid(cgroup, thread.linux_tid)) {
+                       return FRSH_ERR_INTERNAL_ERROR;
+       }
+       
+       /*sched_getparam(thread.linux_tid, &param);
+       if (param.sched_priority == 0) {
+               param.sched_priority = 1;
+               if (sched_setscheduler(thread.linux_tid, SCHED_RR, 
+                       &param) == -1) {
+                       return FRSH_ERR_INTERNAL_ERROR;
+               }
+       }*/
+
+       return FRSH_NO_ERROR; 
+}
+
+/*
+ * frsh_thread_unbind(), unbind a thread from a vres
+ *
+ * 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)
+{
+       /* TODO: solve thread -> vres mapping */
+#if 0
+       char path[FILENAME_MAX];
+       struct cgroup* cgroup = (struct cgroup*)vres->priv;
+       FILE* taskf;
+
+       /*if (!aqcpu_is_initialized) {
+                 return(FRSH_ERR_NOT_INITIALIZED);
+       }*/
+       
+       if (!cg_build_path(cgroup->name, path, cgroup->controller[i]->name)){
+               return FRSH_ERR_INTERNAL_ERROR;
+       }
+       
+       strcat(path, "tasks");
+       taskf = fopen(path, "w");
+       if (!taskf) {
+               return FRSH_ERR_INTERNAL_ERROR;
+       }
+       fclose(taskf);
+#endif
+       return FRSH_NO_ERROR; 
+}
+
+/**
+ * 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;   
+       
+       *thread_id = fosa_thread_self();
+       /* bind this thread to vres */
+       pth->errcode = frsh_thread_bind(pth->vres, *thread_id);
+       
+       sem_post(pth->stopper); 
+       if (pth->errcode) /* vres binding was not successful */
+               return NULL;
+
+       /* execute thread function */   
+       return pth->pthread_code(pth->pthread_arg);
+}
+
+/*
+ * 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 synchronization mechanism based on semaphore is realized.
+ *
+ * possible return values:
+ *  see below the comments of each specific API call
+ */
+
+/*
+ * 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;
+       int rv;
+       sem_t stopper;
+       struct sched_param param;
+       int p;
+
+       sem_init(&stopper, 0, 0);
+       
+       /* 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");
+       */
+
+       wp.parent_thread_id = fosa_thread_self();
+       wp.thread_id = thread;  
+       wp.pthread_code = thread_code;
+       wp.pthread_arg = arg;   
+       wp.vres = vres;
+       wp.stopper = &stopper;
+
+       pthread_attr_getschedparam(attr, &param);
+       p = param.sched_priority;
+       printf("priority = %d\n", p);
+       if (p == 0) {
+               param.sched_priority = 1;
+               pthread_attr_setschedparam(attr, &param);
+               pthread_attr_getschedparam(attr, &param);
+               printf("changed priority = %d\n", param.sched_priority);
+               pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
+               pthread_attr_setschedpolicy(attr, SCHED_RR);
+               pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM);
+       }
+       
+       /* create the wrapper thread */ 
+       rv = fosa_thread_create(thread, attr, wrapper_pthread, (void*)&wp);
+       if (rv != 0)
+               return(rv);
+       
+       sem_wait(&stopper);
+       return (wp.errcode);
+}
+
+/*
+ * 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)
+{
+       return FRSH_ERR_NOT_IMPLEMENTED; 
+}
+
+/*
+ * 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)
+{
+       return FRSH_ERR_NOT_IMPLEMENTED; 
+}
+
+/*
+ * 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)
+{
+       return FRSH_ERR_NOT_IMPLEMENTED; 
+}
+
+
+
+/////////////////////////////////////////////
+// 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)
+{
+       return FRSH_ERR_NOT_IMPLEMENTED; 
+}
+
+/*
+ * 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)
+{
+
+       return FRSH_ERR_NOT_IMPLEMENTED; 
+}
diff --git a/resources/cpucg/lib/timespec_usec_ops.h b/resources/cpucg/lib/timespec_usec_ops.h
new file mode 100644 (file)
index 0000000..57cc989
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef        __TIMESPEC_USEC_OPS_H__
+#define __TIMESPEC_USEC_OPS_H__
+
+/*
+ * timespec_usec_ops.h
+ *
+ * ...
+ */
+
+#include <time.h>
+
+#define equal_timespec(t1, t2) \
+ ( ( (t1)->tv_sec == (t2)->tv_sec ) && ( (t1)->tv_nsec == (t2)->tv_nsec )  )
+
+#define increment_timespec(t) \
+do { \
+ (t)->tv_nsec ++; \
+ if ((t)->tv_nsec >= 1000000000UL) { \
+   (t)->tv_sec ++; \
+   (t)->tv_nsec -= 1000000000UL; \
+ } \
+} while(0)
+
+#define decrement_timespec(t) \
+do { \
+ if ( (t)->tv_nsec == 0) { \
+  (t)->tv_nsec = 1000000000UL; \
+  (t)->tv_sec --; \
+ } \
+ else \
+  (t)->tv_nsec --; \
+} while(0)
+
+#define sum_timespec(t1, t2, ts) \
+do { \
+ (ts)->tv_sec  = (t1)->tv_sec  + (t2)->tv_sec; \
+ (ts)->tv_nsec = (t1)->tv_nsec + (t2)->tv_nsec; \
+ while ( (ts)->tv_nsec >= 1000000000UL) { \
+  (ts)->tv_sec ++; \
+  (ts)->tv_nsec -= 1000000000UL; \
+ } \
+} while(0)
+
+#define sub_timespec(t1, t2, ts) \
+do { \
+ if ( (t2)->tv_sec < (t1)->tv_sec || \
+  ((t2)->tv_sec == (t1)->tv_nsec && (t2)->tv_nsec < (t1)->tv_nsec) ) { \
+  (ts)->tv_sec = (t1)->tv_sec - (t2)->tv_sec; \
+  (ts)->tv_nsec = (t1)->tv_nsec - (t2)->tv_sec; \
+  while ( (ts)->tv_nsec < 0) { \
+   (ts)->tv_sec --; \
+   (ts)->tv_nsec = (ts)->tv_nsec + 1000000000UL; \
+  } \
+ } else { \
+  (ts)->tv_sec = 0UL; \
+  (ts)->tv_nsec = 0UL; \
+ } \
+} while(0)
+
+#define zero_timespec(t) \
+do { \
+ (t)->tv_sec = 0; \
+ (t)->tv_nsec = 0; \
+} while(0)
+
+#define is_zero_timespec(t) \
+( (t)->tv_sec == 0 && (t)->tv_nsec == 0 )
+
+#endif /* __TIMESPEC_USEC_OPS_H__ */
diff --git a/resources/cpucg/mngr/Makefile b/resources/cpucg/mngr/Makefile
new file mode 100644 (file)
index 0000000..b22a357
--- /dev/null
@@ -0,0 +1,14 @@
+# Generic directory or leaf node makefile for OCERA make framework
+
+ifndef MAKERULES_DIR
+MAKERULES_DIR := $(shell ( old_pwd="" ;  while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd`  ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) )
+endif
+
+ifeq ($(MAKERULES_DIR),)
+all : default
+.DEFAULT::
+       @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n"
+else
+include $(MAKERULES_DIR)/Makefile.rules
+endif
+
diff --git a/resources/cpucg/mngr/Makefile.omk b/resources/cpucg/mngr/Makefile.omk
new file mode 100644 (file)
index 0000000..60d0571
--- /dev/null
@@ -0,0 +1,4 @@
+bin_PROGRAMS = cpucgmngr
+cpucgmngr_SOURCES = cpucg_mngr.c
+cpucgmngr_LIBS = frm forb contract fosa rt ulut fcb_client
+lib_LOADLIBES+= frsh
diff --git a/resources/cpucg/mngr/cpucg_mngr.c b/resources/cpucg/mngr/cpucg_mngr.c
new file mode 100644 (file)
index 0000000..08df63a
--- /dev/null
@@ -0,0 +1,138 @@
+/**************************************************************************/
+/* ---------------------------------------------------------------------- */
+/* Copyright (C) 2006 - 2008 FRESCOR consortium partners:                */
+/*                                                                       */
+/*   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 for a link to partners' websites         */
+/*                                                                       */
+/*          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.                                              */
+/*                                                                       */
+/*                                                                       */
+/*  This file is part of FRESCOR CPUCG (cpu control group)               */
+/*                                                                       */
+/* FWP is free software; you can redistribute it and/or modify it        */
+/* under terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2, or (at your option) any   */
+/* later version.  FWP 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 along with FWP; see file       */
+/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,  */
+/* Cambridge, MA 02139, USA.                                             */
+/*                                                                       */
+/* As a special exception, including FWP header files in a file,         */
+/* instantiating FWP generics or templates, or linking other files       */
+/* with FWP objects to produce an executable application, does not       */
+/* by itself cause the resulting executable application to be covered    */
+/* 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 Public License.                                    */
+/**************************************************************************/
+#include <frm_generic.h>
+#include <forb.h>
+#include <error.h>
+#include <errno.h>
+#include <fres_sa_scenario.h>
+#include <stdbool.h>
+#include <ul_log.h>
+#include <stdio.h>
+
+UL_LOG_CUST(ulogd_frm_cpucg);
+ul_log_domain_t ulogd_fra_fwp = {UL_LOGL_DEB, "frm_cpucg"};
+
+/**
+ * root cgroup`s period
+ */
+static unsigned int global_period_us;
+/**
+ * root cgroup`s runtime 
+ */
+static unsigned int global_runtime_us;
+
+static int cpucg_admtest(struct fres_sa_scenario *scenario, void *priv, 
+                               bool *schedulable)
+{
+       struct fres_sa_contract *c;
+       long int period, budget;
+       long int sum_utilization = 0;
+
+       fres_sa_scenario_for_each_contract(scenario, c) {
+               fres_block_basic *basic;
+               char id[40];
+               fres_contract_id_to_string(id, &c->contract->id, sizeof(id));
+               basic = fres_contract_get_basic(c->contract);
+
+               period = fosa_rel_time_to_msec(basic->period);
+               budget = fosa_rel_time_to_msec(basic->budget);
+               printf("processing : id=%s, period=%ld ms, budget=%ld ms\n",
+                      id,period, budget);
+               //ul_logdeb("processing : id=%s, period=%ld ms, budget=%ld ms\n",
+                 //     id,period, budget);
+               
+               sum_utilization+= budget*100/period;
+       }
+       printf("sum_ut= %ld  global_ut=%ld \n", sum_utilization, (global_runtime_us*100/global_period_us));
+       *schedulable = (sum_utilization < (global_runtime_us*100/global_period_us));
+       printf("=> %s\n", (*schedulable)?"schedulable":"not schedulable");
+               
+       return 0;
+}
+
+static const struct fres_res_manager frm = {
+       .res_type = FRSH_RT_PROCESSOR,
+       .res_id = 0,
+       .admission_test = cpucg_admtest,
+       .priv = NULL
+};
+
+int main(int argc, char *argv[])
+{
+       forb_orb orb;
+       FILE* fd;
+       int ret;
+
+       orb = forb_init(&argc, &argv, "frm_cpucg");
+       if (!orb) error(1, errno, "forb_init");
+       
+       if (!(fd = fopen("/proc/sys/kernel/sched_rt_period_us", "r"))) {
+               error(1, errno, "frm_generic_run");
+       }
+       ret = fscanf(fd,"%d", &global_period_us);
+       printf("sched_rt_period_us= %d\n", global_period_us);
+       if (ret == 0 || ret == EOF) {
+               error(1, errno, "frm_generic_run");
+       }
+       fclose(fd);
+
+       if (!(fd = fopen("/proc/sys/kernel/sched_rt_runtime_us", "r"))) {
+               error(1, errno, "frm_generic_run");
+       }
+       ret = fscanf(fd,"%d", &global_runtime_us);
+       printf("sched_rt_runtime_us= %d\n", global_runtime_us);
+       if (ret == 0 || ret == EOF) {
+               error(1, errno, "frm_generic_run");
+       }
+       fclose(fd);
+       
+       ret = frm_register_and_run(orb, &frm);
+       if (ret != 0) {
+               error(1, errno, "frm_generic_run");
+       }
+       
+       return 0;
+}
diff --git a/resources/cpucg/tests/Makefile b/resources/cpucg/tests/Makefile
new file mode 100644 (file)
index 0000000..b22a357
--- /dev/null
@@ -0,0 +1,14 @@
+# Generic directory or leaf node makefile for OCERA make framework
+
+ifndef MAKERULES_DIR
+MAKERULES_DIR := $(shell ( old_pwd="" ;  while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd`  ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) )
+endif
+
+ifeq ($(MAKERULES_DIR),)
+all : default
+.DEFAULT::
+       @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n"
+else
+include $(MAKERULES_DIR)/Makefile.rules
+endif
+
diff --git a/resources/cpucg/tests/Makefile.omk b/resources/cpucg/tests/Makefile.omk
new file mode 100644 (file)
index 0000000..f93b82b
--- /dev/null
@@ -0,0 +1,4 @@
+test_PROGRAMS = cpucgtest
+cpucgtest_SOURCES = cpucgtest.c
+#aqcpumngr_LIBS = frm forb contract fosa rt ulut fcb_client
+lib_LOADLIBES += pthread rt frshcpucg frsh 
diff --git a/resources/cpucg/tests/config.omk b/resources/cpucg/tests/config.omk
new file mode 100644 (file)
index 0000000..906e662
--- /dev/null
@@ -0,0 +1,7 @@
+CONFIG_AQUOSA=y
+CFLAGS+=-save-temps
+CONFIG_FWP=n
+CONFIG_RESOURCE_DUMMY=n
+CONFIG_RESOURCE_ITEM=n
+CONFIG_RESOURCE_CLUSTER_TREE=n
+
diff --git a/resources/cpucg/tests/cpucgtest.c b/resources/cpucg/tests/cpucgtest.c
new file mode 100644 (file)
index 0000000..564dec9
--- /dev/null
@@ -0,0 +1,62 @@
+#include <frsh.h>
+#include <cpucg_res.h>
+#include <error.h>
+
+void* work_thread()
+{
+       int i;
+
+       printf("I am alive! \n");
+       while(1) {
+               printf("I am alive! \n");
+               i++;
+
+       }
+
+}
+
+int main()
+{
+       frsh_vres_id_t vres;
+       frsh_thread_attr_t attr;
+       frsh_thread_id_t thread;
+       frsh_contract_t contract;
+       frsh_rel_time_t budget, period;
+       int ret;
+
+       if (frsh_init()) {
+               error(1, 0, "FRSH initialization failed\n");
+
+       }
+       
+       /* Contract negotiation for CPU */
+       ret = frsh_contract_init(&contract);
+       if (ret) PERROR_AND_EXIT(ret, "frsh_contract_init");
+               
+       budget = fosa_msec_to_rel_time(50);
+       period = fosa_msec_to_rel_time(100);
+       ret = frsh_contract_set_basic_params(&contract,
+                                            &budget,
+                                            &period,
+                                            FRSH_WT_BOUNDED,
+                                            FRSH_CT_REGULAR);
+       if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_basic_params");
+       ret = frsh_contract_set_resource_and_label(&contract, FRSH_RT_PROCESSOR,
+                                                       0,"aqcpu_cont1");
+       if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_resource_and_label");
+
+       ret = frsh_contract_negotiate(&contract, &vres);
+       if (ret) PERROR_AND_EXIT(ret, "frsh_contract_negotiate");
+
+       printf("Aqcpu vres negotiated\n");
+       pthread_attr_init(&attr);
+       ret = frsh_thread_create_and_bind(vres, &thread, &attr, 
+                               work_thread, (void*) NULL);
+       if (ret) PERROR_AND_EXIT(ret, "frsh_thread_create_and_bind");
+       
+       pthread_join(thread.pthread_id, (void**) NULL); 
+       printf("Test PASSED!\n");
+               
+       return 0;       
+}
+