#include <forb/server_id.h>
#include <fres_contract.h>
#include "fcb_config.h"
-
+#include <fosa_clocks_and_timers.h>
#ifdef CONFIG_FCB_INET
#include <forb/proto_inet.h>
#endif
UL_LOG_CUST(ulogd_fcb);
ul_log_domain_t ulogd_fcb = {UL_LOGL_MSG, "fcb"};
+fosa_abs_time_t start_time;
+
/**
* Resource identification
struct res_key key;
fres_resource_manager mng; /**< Object reference of the resource manager */
gavl_cust_root_field_t allocators; /**< Registered allocators for this resource (from multiple applications/nodes) */
+ ul_list_head_t sc_contracts; /**< Negotiated contracts with spare capacity for this resource */
};
/**
struct fcb_contract {
fres_contract_id_t id;
- gavl_node_t node;
+ gavl_node_t node_fcb;
+ ul_list_node_t node_sc;
+ int next_sc_variant;
+ int reserved_sc_variant;
+ fosa_abs_time_t end_of_stability_period;
struct fres_contract *user_contract;
+ struct fres_contract *reserved_contract;
+ struct fres_contract *to_be_reserved_contract;
};
/**
app /* cust_item_key */, \
forb_server_id_cmp /* cust_cmp_fnc */);
+/* Container for contracts with spare capacity negotiated for a given resource */
+UL_LIST_CUST_DEC(sc_contracts /* cust_prefix */, \
+ struct resource /* cust_head_t */, \
+ struct fcb_contract /* cust_item_t */, \
+ sc_contracts /* cust_head_field */, \
+ node_sc /* cust_node_field */);
+
/* Container for negotiated contracts */
GAVL_CUST_NODE_INT_DEC(fcb_contract /* cust_prefix */, \
struct fcb /* cust_root_t */, \
struct fcb_contract /* cust_item_t */, \
fres_contract_id_t /* cust_key_t */, \
contracts /* cust_root_node */, \
- node /* cust_item_node */, \
+ node_fcb /* cust_item_node */, \
id /* cust_item_key */, \
fres_contract_id_cmp /* cust_cmp_fnc */);
struct fcb_contract /* cust_item_t */, \
fres_contract_id_t /* cust_key_t */, \
contracts /* cust_root_node */, \
- node /* cust_item_node */, \
+ node_fcb /* cust_item_node */, \
id /* cust_item_key */, \
fres_contract_id_cmp /* cust_cmp_fnc */);
#else
{
struct resource *resource = NULL;
unsigned i;
- struct res_key key, key2;
+ struct res_key key, key2 = {-1,-1};
for (i=0; i<num; i++) {
if (!get_res_key(fcb, contracts[i], &key)) {
struct fres_contract *c = contracts[i];
if (fres_contract_id_is_empty(&c->id)) {
+ /* Normal negotiation request */
forb_uuid_generate((forb_uuid_t *)&c->id);
continue;
}
return 0;
}
+static int prepare_next_reservation_variant(struct fcb_contract *fc, fosa_abs_time_t now)
+{
+ fres_block_spare_capacity *s;
+ fres_contract_destroy(fc->to_be_reserved_contract);
+ fc->to_be_reserved_contract = fres_contract_duplicate(fc->user_contract);
+ if (!fc->to_be_reserved_contract)
+ return errno;
+ s = fres_contract_get_spare_capacity(fc->to_be_reserved_contract);
+ if (s) {
+ int variant;
+ variant = fosa_abs_time_smaller(fc->end_of_stability_period, now) ?
+ fc->next_sc_variant :
+ fc->reserved_sc_variant;
+
+ fres_container_copy(fc->to_be_reserved_contract->container,
+ forb_sequence_elem(s->variants, variant));
+ }
+}
+
+static int
+rebalance_spare_capacity_and_reserve(struct fcb *fcb, struct resource *resource,
+ struct fcb_contract *fcb_contract[], int num)
+{
+ unsigned i;
+ fosa_abs_time_t now;
+ fosa_clock_get_time(CLOCK_REALTIME, &now);
+ for (i=0; i<num; i++) {
+ prepare_next_reservation_variant(fcb_contract[i], now);
+ }
+#if 0
+ do {
+ /* Reserve contract */
+ ret = fres_resource_manager_reserve_contracts(resource->mng, contracts, ev);
+ if (forb_exception_occurred(ev) || ret < 0) {
+ return ret;
+ }
+ } while (ret != 0)
+#endif
+ return 0;
+}
+
CORBA_long
negotiate_contracts(fres_contract_broker obj,
const fres_contract_ptr_seq* contracts,
ret = prepare_reservation_contracts(fcb, contracts->_buffer, contracts->_length);
if (ret)
goto err;
-
+
forb_get_req_source(obj, &app);
ra = fcb_alloc_find(resource, &app);
if (!ra) {
/* Allocate all the needed memory before doing reservation. If
* there is no enough memory, it has no sense to call resource
* manager. */
+ /* TODO: Use FORB macros to allocate sequence */
ids = malloc(sizeof(*ids));
if (!ids) {
ev->major = FORB_EX_NO_MEMORY;
memset(fcb_contracts, 0, sizeof(fcb_contracts[0])*contracts->_length);
for (i=0; i<contracts->_length; i++) {
+ /* Allocate FCB contracts */
struct fres_contract *c = contracts->_buffer[i];
if (fres_contract_get_num_blocks(c) > 0) {
fcb_contracts[i] = fcb_contract_new(&c->id);
/* TODO: Optimize the following by introducing
* reserve_and_commit FRM method. */
-
+#if 1
/* Reserve contract */
ret = fres_resource_manager_reserve_contracts(resource->mng, contracts, ev);
if (forb_exception_occurred(ev) || ret < 0) {
goto err_free_fcb_contracts;
}
+#else
+ ret = rebalance_spare_capacity_and_reserve(fcb, resource, contracts->_buffer,
+ fcb_contracts, contracts->_length);
+#endif
if (ret == 1) {
- ul_logmsg("Contract was not accepted\n");
+ ul_logmsg("Contract(s) was not accepted\n");
goto err_free_fcb_contracts;
}
res->mng = forb_object_duplicate(desc->manager);
fcb_alloc_init_root_field(res);
+ sc_contracts_init_head(res);
ul_logmsg("Registering manager for resource %d.%d\n",
restype, resid);
fcb_resource_insert(fcb, res);
.get_resources = get_resources,
};
+void peer_discovery_callback(const forb_orb peer_orb, const char *orb_id)
+{
+ forb_server_id server_id;
+ char server_id_str[sizeof(forb_server_id)*2+1];
+
+ forb_get_server_id(peer_orb, &server_id);
+ forb_server_id_to_string(server_id_str, &server_id, sizeof(server_id_str));
+#if 0
+ ul_logmsg("peer discovered: %s (orb_id '%s')\n", server_id_str, orb_id);
+#endif
+ if (strcmp(orb_id, "org.frescor.fcb") == 0) {
+ fosa_abs_time_t now;
+ fosa_rel_time_t delay;
+ fosa_clock_get_time(CLOCK_REALTIME, &now);
+ delay = fosa_abs_time_extract_interval(start_time, now);
+ ul_logmsg("node joined: %s (time %ld ms)\n", server_id_str,
+ fosa_rel_time_to_msec(delay));
+ }
+}
+
+void peer_dead_callback(const forb_orb peer_orb, const char *orb_id)
+{
+}
+
int main(int argc, char *argv[])
{
forb_orb orb;
fres_contract_broker fcb;
forb_executor_t executor;
int ret;
+ forb_init_attr_t attr = {
+ .orb_id = "org.frescor.fcb",
+ .peer_discovery_callback = peer_discovery_callback,
+ .peer_dead_callback = peer_dead_callback,
+ };
+
+
+ fosa_clock_get_time(CLOCK_REALTIME, &start_time);
- orb = forb_init(&argc, &argv, "fcb");
+ orb = forb_init(&argc, &argv, &attr);
if (!orb) error(1, errno, "FORB initialization failed");
#ifdef CONFIG_FCB_INET
sequence<container_ptr> variants;
};
+ /// Power Management
+ struct power_management {
+ fosa_rel_time_t period;
+ fosa_rel_time_t max_budget[3];
+ fosa_rel_time_t min_budget[3];
+ fosa_rel_time_t min_expiration;
+ };
+
};
};
.to_string = fres_block_##type##_to_string \
}
+static size_t indent_str(char *dest, size_t size, char *src, unsigned indent_by)
+{
+ char *p = src;
+ size_t written = 0;
+ while (*p && size > 1) {
+ if (p == src || *(p-1) == '\n') { /* indent */
+ int i;
+ for (i=0; i<indent_by; i++) {
+ *dest++ = ' ';
+ written++;
+ size--;
+ }
+ }
+ *dest++ = *p++;
+ written++;
+ size--;
+ }
+ *dest = 0;
+ return written;
+}
+
int fres_block_label_to_string(char *dest, size_t size, enum fres_block_type type,
const void *block_data)
{
);
}
+int fres_block_spare_capacity_to_string(char *dest, size_t size, enum fres_block_type type,
+ const void *block_data)
+{
+ int i, ret;
+ char *orig_dest = dest;
+ const fres_block_spare_capacity *s = block_data;
+ ret = snprintf(dest, size,
+ "granularity: %s\n"
+ "importance: %d\n"
+ "weight: %d\n"
+ "stability time: %g\n",
+ s->granularity == FRSH_GR_CONTINUOUS ? "continuous" :
+ s->granularity == FRSH_GR_DISCRETE ? "discrete" : "?",
+ s->importance, s->weight, fosa_rel_time_to_double(s->stability_time));
+ dest += ret;
+ size -= ret;
+ for (i=0; i < s->variants._length; i++) {
+ char tmp[1000];
+ ret = snprintf(dest, size, "Variant %d:\n", i);
+ dest += ret;
+ size -= ret;
+ ret = fres_container_to_string(tmp, sizeof(tmp),
+ forb_sequence_elem(s->variants, i));
+ ret = indent_str(dest, size, tmp, 2);
+ dest += ret;
+ size -= ret;
+ }
+ return dest - orig_dest;
+}
+
int fres_block_csects_to_string(char *dest, size_t size, enum fres_block_type type,
const void *block_data)
{
return snprintf(dest, size, "Coming Soon...\n");
}
+int fres_block_power_management_to_string(char *dest, size_t size, enum fres_block_type type,
+ const void *block_data)
+{
+ return snprintf(dest, size, "Coming Soon...\n");
+}
+
static const desc_default(label);
static const desc_default(resource);
static const desc_default(basic);
static const desc_default(timing_reqs);
static const desc_default(csects);
+static const desc_default(power_management);
static const struct fres_block_desc desc_spare_capacity = {
+ .name = "spare_capacity",
.size = sizeof(fres_block_spare_capacity),
.serialize = (fres_block_serialize_fnc_t*)fres_block_spare_capacity_serialize, \
.deserialize = (fres_block_deserialize_fnc_t*)fres_block_spare_capacity_deserialize, \
- .duplicate = fres_block_duplicate_spare_capacity
+ .duplicate = fres_block_duplicate_spare_capacity,
+ .to_string = fres_block_spare_capacity_to_string
};
/**
[FRES_BLOCK_BASIC] = &desc_default_basic,
[FRES_BLOCK_TIMING_REQS] = &desc_default_timing_reqs,
[FRES_BLOCK_CSECTS] = &desc_default_csects,
+ [FRES_BLOCK_SPARE_CAPACITY] = &desc_spare_capacity,
+ [FRES_BLOCK_POWER_MANAGEMENT] = &desc_default_power_management,
};
/**
}
if (block_registry[type]->to_string) {
char tmp[1000];
- char *p = tmp;;
- ret = block_registry[type]->to_string(tmp, sizeof(tmp), type, b->u.data);
- while (*p) {
- if (p == tmp || *(p-1) == '\n') { /* indent */
- int i;
- for (i=0; i<2; i++) {
- *dest++ = ' ';
- written++;
- size--;
- }
- }
- *dest++ = *p++;
- written++;
- size--;
- }
+ block_registry[type]->to_string(tmp, sizeof(tmp), type, b->u.data);
+ ret = indent_str(dest, size, tmp, 2);
+ written += ret;
+ size -= ret;
+ dest += ret;
}
break;
case FRES_BLOCK_STREAM:
}
}
ret = written;
+ *dest = 0;
err:
return ret;
}
}
return 0;
}
+
+/**
+ * Copy blocks from a container into another one. Blocks present in
+ * both @a src and @a dest are replaced in @a dest.
+ *
+ * @param dest Destination of copy operation
+ * @param src Source of copy operation
+ *
+ * @return Zero on success, non-zero error core on error.
+ */
+int fres_container_copy(struct fres_container *dest,
+ const struct fres_container *src)
+{
+ enum fres_block_type type;
+ int ret;
+
+ for (type=0; type<FRES_NUM_BLOCKS; type++) {
+ const struct fres_block *sb = &src->blocks[type];
+ struct fres_block *db = &dest->blocks[type];
+
+ if (sb->state != FRES_BLOCK_EMPTY) {
+ fres_container_del_block(dest, type);
+ ret = fres_block_duplicate(db, sb, type);
+ if (ret) {
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
FRES_BLOCK_TIMING_REQS,
FRES_BLOCK_CSECTS,
FRES_BLOCK_SPARE_CAPACITY,
+ FRES_BLOCK_POWER_MANAGEMENT,
FRES_BLOCK_DUMMY_SCHED, /**< See resources/dummy/res_dummy_idl.idl */
+ FRES_BLOCK_DISK_SCHED, /** < See resources/disk_bfq/res_disk_idl.idl */
FRES_BLOCK_CLUSTER_TREE_TRAFFIC, /**< resources/cluster_tree/cluster_tree_idl.idl */
FRES_BLOCK_FWP_SCHED,
FRES_BLOCK_ITEM_NODES, /**< resources/item/item_idl.idl */
FRES_CONTAINER_ACCESSOR(TIMING_REQS, timing_reqs)
FRES_CONTAINER_ACCESSOR(CSECTS, csects)
FRES_CONTAINER_ACCESSOR(SPARE_CAPACITY, spare_capacity)
+FRES_CONTAINER_ACCESSOR(POWER_MANAGEMENT, power_management)
int
fres_block_register(enum fres_block_type, const struct fres_block_desc *desc);
int fres_container_merge(struct fres_container *dest,
const struct fres_container *src);
+int fres_container_copy(struct fres_container *dest,
+ const struct fres_container *src);
+
#ifdef __cplusplus
} /* extern "C"*/
#endif
void fres_contract_destroy(struct fres_contract *contract)
{
- fres_container_destroy(contract->container);
- free(contract);
+ if (contract) {
+ fres_container_destroy(contract->container);
+ free(contract);
+ }
}
struct fres_contract *
FRES_CONTRACT_ACCESSOR(timing_reqs)
FRES_CONTRACT_ACCESSOR(csects)
FRES_CONTRACT_ACCESSOR(spare_capacity)
+FRES_CONTRACT_ACCESSOR(power_management)
#ifdef __cplusplus
} /* extern "C"*/
GAVL_CUST_NODE_INT_IMP(fres_threads_vres_nolock /* cust_prefix */,
struct fres_threads_vres /* cust_root_t */,
struct fres_thread_vres /* cust_item_t */,
- fosa_thread_id_t /* cust_key_t */,
+ fres_thread_vres_key_t /* cust_key_t */,
threads /* cust_root_node */,
node /* cust_item_node */,
- id /* cust_item_key */,
+ thread_vres /* cust_item_key */,
fres_thread_vres_cmp /* cust_cmp_fnc */);
-
/**
* Inserts vres to the global vres "registry".
*
return ret;
}
+struct fres_vres *
+fres_vreses_find_label(fres_block_label *label, fres_block_resource *res)
+{
+ struct fres_vres *item;
+
+ gavl_cust_for_each(fres_vreses_nolock, &fres_vreses, item) {
+ struct fres_contract *c = item->perceived;
+ fres_block_label *l = fres_contract_get_label(c);
+ fres_block_resource *r = fres_contract_get_resource(c);
+
+ if (strncmp(l->label, label->label, sizeof(label->label)) &&
+ res->resource_type == r->resource_type &&
+ res->resource_id == r->resource_id)
+ return item;
+ }
+
+ return NULL;
+}
+
#define save_errno(cmd) do { int _e = errno; cmd; errno = _e; } while(0)
}
static inline
-int fres_threads_vres_insert(struct fres_thread_vres *th)
+int fres_threads_vres_insert(struct fres_thread_vres *tv)
{
int ret;
fosa_mutex_lock(&fres_threads_vres.mutex);
- ret = fres_threads_vres_nolock_insert(&fres_threads_vres, th);
+ ret = fres_threads_vres_nolock_insert(&fres_threads_vres, tv);
fosa_mutex_unlock(&fres_threads_vres.mutex);
return ret;
}
static inline
-int fres_threads_vres_delete(struct fres_thread_vres *th)
+int fres_threads_vres_delete(struct fres_thread_vres *tv)
{
int ret;
fosa_mutex_lock(&fres_threads_vres.mutex);
- ret = fres_threads_vres_nolock_delete(&fres_threads_vres, th);
+ ret = fres_threads_vres_nolock_delete(&fres_threads_vres, tv);
fosa_mutex_unlock(&fres_threads_vres.mutex);
return ret;
}
static inline
-struct fres_thread_vres *fres_threads_vres_find(const fosa_thread_id_t *id)
+struct fres_thread_vres *fres_threads_vres_find(const fres_thread_vres_key_t *key)
{
struct fres_thread_vres *ret;
fosa_mutex_lock(&fres_threads_vres.mutex);
- ret = fres_threads_vres_nolock_find(&fres_threads_vres, id);
+ ret = fres_threads_vres_nolock_find(&fres_threads_vres, key);
fosa_mutex_unlock(&fres_threads_vres.mutex);
return ret;
}
/**
- * Creates binding from a thread to VRES; if binding already exists,
- * it is updated.
+ * Creates binding from a thread to VRES of specified type;
+ * if binding already exists, it fails... The old one should be
+ * deleted first.
*
- * @param id Thread ID bounded to @a vres.
+ * @param id Thread ID bounded to @a vres of type @vres_type.
* @param vres VRES
*
* @return Positive number when a new binding was inserted, zero when
* binding was changed and -1 on error.
*/
-int fra_insert_thread_vres(const fosa_thread_id_t *id, fres_vres_t *vres)
+int fra_insert_thread_vres(const fosa_thread_id_t *id,
+ int vres_type,
+ fres_vres_t *vres)
{
- struct fres_thread_vres *th;
+ fres_thread_vres_key_t key;
+ struct fres_thread_vres *tv;
- th = fres_threads_vres_find(id);
- if (th) {
- fosa_mutex_lock(&fres_threads_vres.mutex);
- th->vres = vres;
- fosa_mutex_unlock(&fres_threads_vres.mutex);
+ key.thread_id = *id;
+ key.vres_type = vres_type;
- return 0;
- }
+ tv = fres_threads_vres_find(&key);
+ if (tv) return -1;
- th = fres_thread_vres_new(id, vres);
- if (!th) return -1;
+ tv = fres_thread_vres_new(id, vres_type, vres);
+ if (!tv) return -1;
- return fres_threads_vres_insert(th);
+ return !fres_threads_vres_insert(tv);
}
/**
*
* @return Zero on success, -1 on when the thread was not bound.
*/
-int fra_delete_thread_vres(const fosa_thread_id_t *id)
+int fra_delete_thread_vres(const fosa_thread_id_t *id, int vres_type)
{
- struct fres_thread_vres *th;
- int ret = 0;
+ struct fres_thread_vres *tv;
+ fres_thread_vres_key_t key;
+ int ret;
+
+ key.thread_id = *id;
+ key.vres_type = vres_type;
fosa_mutex_lock(&fres_threads_vres.mutex);
- th = fres_threads_vres_nolock_find(&fres_threads_vres, id);
- if (th) {
- fres_threads_vres_nolock_delete(&fres_threads_vres, th);
- } else {
+ tv = fres_threads_vres_nolock_find(&fres_threads_vres, &key);
+ if (!tv) {
ret = -1;
+ goto retr;
}
+
+ ret = fres_threads_vres_nolock_delete(&fres_threads_vres, tv);
fosa_mutex_unlock(&fres_threads_vres.mutex);
- if (ret == 0) {
- fres_thread_vres_destroy(th);
- }
+ if (ret) goto retr;
+
+ ret = !fres_threads_vres_delete(tv);
+
+retr:
return ret;
}
* @todo Is this function needed if we have
* fra_get_vres_thread_vres()?
*/
-fres_thread_vres_t *fra_get_thread_vres(const fosa_thread_id_t *id)
+fres_thread_vres_t *fra_get_thread_vres
+ (const fosa_thread_id_t *id,
+ int vres_type)
{
- return fres_threads_vres_find(id);
+ fres_thread_vres_key_t key;
+
+ key.thread_id = *id;
+ key.vres_type = vres_type;
+
+ return fres_threads_vres_find(&key);
}
/**
*
* @return VRES on NULL in the thread is not bound.
*/
-fres_vres_t *fra_get_vres_thread_vres(const fosa_thread_id_t *id)
+fres_vres_t *fra_get_vres_thread_vres
+ (const fosa_thread_id_t *id,
+ int vres_type)
{
- fres_thread_vres_t *th_vres;
+ fres_thread_vres_key_t key;
+ fres_thread_vres_t *tv;
- th_vres = fres_threads_vres_find(id);
- if (!th_vres) return NULL;
+ key.thread_id = *id;
+ key.vres_type = vres_type;
- return th_vres->vres;
+ tv = fres_threads_vres_find(&key);
+ if (!tv) return NULL;
+ return tv->vres;
}
extern struct fres_vreses fres_vreses;
+struct fres_vres *
+fres_vreses_find_label(fres_block_label *label, fres_block_resource *res);
/** Registry of all threads in an application that are bound to a VRES. */
struct fres_threads_vres {
GAVL_CUST_NODE_INT_DEC(fres_threads_vres_nolock /* cust_prefix */,
struct fres_threads_vres /* cust_root_t */,
struct fres_thread_vres /* cust_item_t */,
- fosa_thread_id_t /* cust_key_t */,
+ fres_thread_vres_key_t /* cust_key_t */,
threads /* cust_root_node */,
node /* cust_item_node */,
- id /* cust_item_key */,
+ thread_vres /* cust_item_key */,
fres_thread_vres_cmp /* cust_cmp_fnc */)
extern struct fres_threads_vres fres_threads_vres;
int (*apply_vres_changes)(fres_vres_t *vreses[], unsigned length, void *priv);
/*@}*/
+ /** @name Feedback module support */
+ /*@{*/
+ int (*set_spare_bandwidth)(fres_vres_t *vres);
+ int (*get_desired_budget)(fres_vres_t *vres, frsh_rel_time_t *p_budget_out);
+ int (*set_desired_budget)(fres_vres_t *vres_id, frsh_rel_time_t *p_budget_in);
+ int (*get_actual_budget)(fres_vres_t *vres_id, frsh_rel_time_t *budget);
+ /*@}*/
+
+ int (*bind_thread)(fres_vres_t *vres, fosa_thread_id_t thread);
+ int (*unbind_thread)(fosa_thread_id_t thread);
+
+ int (*vres_get_job_usage)(const fres_vres_t *vres, frsh_rel_time_t *spent);
+ int (*vres_get_remaining_budget)(const fres_vres_t *vres, frsh_rel_time_t *budget);
+ int (*vres_get_usage)(const fres_vres_t *vres, frsh_rel_time_t *spent);
+
void *priv; /**< Pointer to allocator's private data */
/**
int fra_register(struct fres_allocator *allocator);
int fra_activate(frsh_resource_type_t res_type,
frsh_resource_id_t res_id);
+struct fres_allocator *fra_get(frsh_resource_type_t res_type,
+ frsh_resource_id_t res_id);
fres_vres_t *fra_get_vres(fres_contract_id_t *id);
-int fra_insert_thread_vres(const fosa_thread_id_t *id, fres_vres_t *vres);
-int fra_delete_thread_vres(const fosa_thread_id_t *id);
-fres_thread_vres_t *fra_get_thread_vres(const fosa_thread_id_t *id);
-fres_vres_t *fra_get_vres_thread_vres(const fosa_thread_id_t *id);
+int fra_insert_thread_vres(const fosa_thread_id_t *id,
+ int vres_type,
+ fres_vres_t *vres);
+int fra_delete_thread_vres(const fosa_thread_id_t *id,
+ int vres_type);
+fres_thread_vres_t *fra_get_thread_vres(const fosa_thread_id_t *id,
+ int vres_type);
+fres_vres_t *fra_get_vres_thread_vres(const fosa_thread_id_t *id,
+ int vres_type);
#endif
+
return ret;
}
+
+/**
+ * Returns allocator for a given resource, previously registered by
+ * fra_register().
+ *
+ * @param res_type
+ * @param res_id
+ *
+ * @return Pointer to the resource allocator or NULL if no allocator
+ * is registered for the resource.
+ */
+struct fres_allocator *fra_get(frsh_resource_type_t res_type,
+ frsh_resource_id_t res_id)
+{
+ struct registered_allocator *ra;
+ struct fres_allocator key, *pkey=&key;
+
+ pkey->res_type = res_type;
+ pkey->res_id = res_id;
+
+ ra = fra_registry_find(®istry, &pkey);
+ if (ra) {
+ return ra->allocator;
+ } else {
+ return NULL;
+ }
+}
fres_thread_vres_t *fres_thread_vres_new
(const fosa_thread_id_t *id,
+ int vres_type,
fres_vres_t *vres)
{
- fres_thread_vres_t *th;
+ fres_thread_vres_t *tv;
- th = malloc(sizeof(*th));
- if (!th) goto out;
+ tv = malloc(sizeof(*tv));
+ if (!tv) goto out;
- memset(th, 0, sizeof(*th));
- th->id = *id;
- th->vres = vres;
+ memset(tv, 0, sizeof(*tv));
+ tv->thread_vres.thread_id = *id;
+ tv->thread_vres.vres_type = vres_type;
+ tv->vres = vres;
out:
- return th;
+ return tv;
}
-void fres_thread_vres_destroy(fres_thread_vres_t *th_vres)
+void fres_thread_vres_destroy(fres_thread_vres_t *tv)
{
- if (!th_vres) return;
+ if (!tv) return;
- free(th_vres);
+ free(tv);
}
/**
* @file fres_vres.h
* @author Michal Sojka <sojkam1@fel.cvut.cz>
+ * Dario Faggioli <faggioli@gandalf.sssup.it>
* @date Wed Feb 18 16:00:15 2009
*
* @brief VRES definition
/**
* Representation of thread to VRES binding.
*/
+typedef struct fres_thread_vres_key {
+ fosa_thread_id_t thread_id;
+ int vres_type;
+} fres_thread_vres_key_t;
+
typedef struct fres_thread_vres {
- fosa_thread_id_t id;
+ struct fres_thread_vres_key thread_vres;
fres_vres_t *vres;
fosa_abs_time_t job_start_time;
} fres_thread_vres_t;
static inline
-int fres_thread_vres_cmp(const fosa_thread_id_t *a, const fosa_thread_id_t *b)
+int fres_thread_vres_cmp
+ (const fres_thread_vres_key_t *a,
+ const fres_thread_vres_key_t *b)
{
- return fosa_thread_equal(*a, *b);
+ /*
+ * TODO:
+ * Make this a little bit less specific!
+ */
+ if (a->thread_id.linux_tid < a->thread_id.linux_tid)
+ return -1;
+ else if (a->thread_id.linux_tid > a->thread_id.linux_tid)
+ return +1;
+ else if (a->vres_type < b->vres_type)
+ return -1;
+ else if (a->vres_type > b->vres_type)
+ return +1;
+
+ return 0;
}
-fres_thread_vres_t *fres_thread_vres_new
- (const fosa_thread_id_t *id,
- fres_vres_t *vres);
+fres_thread_vres_t *fres_thread_vres_new(const fosa_thread_id_t *id,
+ int vres_type,
+ fres_vres_t *vres);
-void fres_thread_vres_destroy(fres_thread_vres_t *th_vres);
+void fres_thread_vres_destroy(fres_thread_vres_t *tv);
#endif
+
SUBDIRS = tests
shared_LIBRARIES = frsh
-frsh_SOURCES = frsh_contract.c frsh_vres.c frsh_synchobj.c frsh_distributed.c frsh_core.c frsh_spare_capacity.c frsh_error.c frsh_thread.c frsh_sharedobj.c
+frsh_SOURCES = frsh_contract.c frsh_vres.c frsh_synchobj.c frsh_distributed.c frsh_core.c \
+ frsh_spare_capacity.c frsh_error.c frsh_thread.c frsh_sharedobj.c frsh_power.c frsh_feedback.c
include_HEADERS = frsh_opaque_types.h frsh_forb.h
-frsh_LIBS = fna fcb_client forb contract synchobj sharedobj fra ulut fosa $(allocator-libs-y)
+frsh_LIBS = fna fcb_client forb contract synchobj sharedobj fra ulut fosa $(allocator-libs-y) $(platform-libs-y)
config_include_HEADERS = frsh_resources.h
frsh_resources_DEFINES = CONFIG_RESOURCE_DUMMY \
CONFIG_AQUOSA\
CONFIG_CPUCG\
+ CONFIG_DISKBFQ\
CONFIG_FWP \
- CONFIG_RESOURCE_ITEM
+ CONFIG_RESOURCE_ITEM \
+ CONFIG_ACPI_LCD \
+ CONFIG_ACPI_CPU \
+ CONFIG_ACPI_BATTERY
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
+allocator-libs-$(CONFIG_DISKBFQ) += frshdiskbfq
+
+platform-libs-$(CONFIG_ACPI_CPU) += acpi_cpu
+platform-libs-$(CONFIG_ACPI_LCD) += acpi_lcd
+platform-libs-$(CONFIG_ACPI_BATTERY) += acpi_battery
ifneq ($(AQUOSA_ROOT),)
LOADLIBES += -L $(AQUOSA_ROOT)/lib
#include <fcb.h>
#include "frsh_forb.h"
#include <fra_generic.h>
+#include <frsh_energy_management.h>
/**********************************/
/* -----===== FRSH API =====----- */
return 0;
}
-int frsh_get_resource_and_label
+int frsh_contract_get_resource_and_label
(const frsh_contract_t *contract,
frsh_resource_type_t *resource_type,
frsh_resource_id_t *resource_id,
return 0;
}
+static
+int __contract_check_min_expiration(const frsh_contract_t *contract)
+{
+ fres_block_power_management *p;
+ int ret = 0;
+
+ p = fres_contract_get_power_management(*contract);
+ if (p && !fosa_rel_time_is_null(p->min_expiration)) {
+ frsh_abs_time_t req_time, exp_time;
+
+ fosa_clock_get_time(FOSA_CLOCK_REALTIME, &req_time);
+ req_time = fosa_abs_time_incr(req_time, p->min_expiration);
+
+ ret = frsh_battery_get_expiration(&exp_time);
+ if (ret) goto err;
+
+ if (fosa_abs_time_smaller(req_time, exp_time))
+ ret = FRSH_ERR_CONTRACT_REJECTED;
+ }
+
+err:
+ return ret;
+}
+
+
int frsh_contract_negotiate
(const frsh_contract_t *contract,
frsh_vres_id_t *vres)
goto err;
}
+ /* TODO: Battery time check should be moved to
+ * FCB. Implementation of FRSH API is meant only as a thin
+ * wrapper of FRES framework and the FRES framework could
+ * theoretically be used without FRSH API. Moreover, if there
+ * is some logging mechanism in FCB, this contract rejection
+ * will not be logged. */
+ ret = __contract_check_min_expiration(contract);
+ if (ret) goto err;
+
/* Activate allocator */
r = fres_contract_get_resource(*contract);
if (r) {
goto out;
}
+ ret = __contract_check_min_expiration(new_contract);
+ if (ret) goto out;
+
contract = fres_contract_duplicate(*new_contract);
if (!contract) {
ret = errno;
#include <cpucg_res.h>
#endif
+#ifdef CONFIG_DISKBFQ
+#include <diskbfq_res.h>
+#endif
+
#ifdef CONFIG_RESOURCE_DUMMY
#include <res_dummy.h>
#endif
int frsh_init()
{
int ret;
+ struct forb_init_attr attr = {
+ .orb_id = "org.frescor.frsh_app"
+ };
- frsh_forb_global.orb = forb_init(NULL, NULL, "frsh");
+ frsh_forb_global.orb = forb_init(NULL, NULL, &attr);
if (!frsh_forb_global.orb) {
- if (errno) return errno;
- else return -1;
+ ret = errno;
+ goto err;
}
frsh_forb_global.fcb = forb_resolve_reference(frsh_forb_global.orb,
if (ret) goto err;
#endif
+#ifdef CONFIG_DISKBFQ
+ ret = diskbfq_fra_init();
+ if (ret) goto err;
+#endif
+
#ifdef FRSH_DISTRIBUTED_MODULE_SUPPORTED
ret = frsh_distributed_init();
if (ret) goto err;
return 0;
err:
+ if (ret == -1) ret = errno;
return ret;
}
--- /dev/null
+/**************************************************************************/
+/* ---------------------------------------------------------------------- */
+/* 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 FRSH (FRescor ScHeduler) */
+/* */
+/* FRSH 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. FRSH 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 FRSH; see file */
+/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
+/* Cambridge, MA 02139, USA. */
+/* */
+/* As a special exception, including FRSH header files in a file, */
+/* instantiating FRSH generics or templates, or linking other files */
+/* with FRSH 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. */
+/**************************************************************************/
+
+/**
+ * @file frsh_feedback.c
+ * @author Dario Faggioli <faggioli@gandalf.sssup.it>
+ * @date Wed Feb 20 14:53:22 2009
+ *
+ * @brief Feedback module of FRSH_FORB framework
+ *
+ */
+
+#include <frsh_core.h>
+#include <fra_generic.h>
+#include "frsh_forb.h"
+#include <frsh_resources.h>
+
+#ifdef CONFIG_AQUOSA
+#include <aqcpu_res.h>
+#endif
+#ifdef CONFIG_CPUCG
+#include <cpucg_res.h>
+#endif
+#ifdef CONFIG_DISKBFQ
+#include <diskbfq_res.h>
+#endif
+
+static frsh_vres_id_t spare_vres;
+
+int frsh_feedback_get_spare(frsh_contract_t *spare_contract)
+{
+ return frsh_vres_get_contract(spare_vres, spare_contract);
+}
+
+int frsh_feedback_set_spare
+ (const frsh_contract_t *spare_contract)
+{
+ int ret = 0;
+ frsh_vres_id_t spare_vres;
+
+ if (!spare_contract || !*spare_contract)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ ret = frsh_contract_negotiate(spare_contract, &spare_vres);
+ if (ret) return ret;
+
+
+ if (spare_vres->allocator->set_spare_bandwidth) {
+ ret = spare_vres->allocator->set_spare_bandwidth(spare_vres);
+ } else {
+ ret = FRSH_ERR_NOT_IMPLEMENTED;
+ }
+
+ return ret;
+}
+
+int frsh_feedback_get_desired_budget
+ (frsh_vres_id_t vres_id,
+ frsh_rel_time_t *p_budget_out)
+{
+ if (vres_id->allocator->get_desired_budget) {
+ return vres_id->allocator->get_desired_budget(vres_id, p_budget_out);
+ } else {
+ return FRSH_ERR_NOT_IMPLEMENTED;
+ }
+}
+
+int frsh_feedback_set_desired_budget
+ (frsh_vres_id_t vres_id,
+ frsh_rel_time_t *p_budget_in)
+{
+ if (vres_id->allocator->set_desired_budget) {
+ return vres_id->allocator->set_desired_budget(vres_id, p_budget_in);
+ } else {
+ return FRSH_ERR_NOT_IMPLEMENTED;
+ }
+}
+
+int frsh_feedback_get_actual_budget
+ (frsh_vres_id_t vres_id,
+ frsh_rel_time_t *budget)
+{
+ if (vres_id->allocator->get_actual_budget) {
+ return vres_id->allocator->get_actual_budget(vres_id, budget);
+ } else {
+ return FRSH_ERR_NOT_IMPLEMENTED;
+ }
+}
+
--- /dev/null
+/**
+ * @file frsh_power.c
+ * @author Michael Trimarchi <trimarchimichael@yahoo.it>
+ * Dario Faggioli <faggioli@gandalf.sssup.it>
+ *
+ * @brief FRSH core thread related functions not implamented in managers..
+ *
+ *
+ */
+
+#include <string.h>
+
+#include <fres_contract.h>
+#include <fres_contract_idl.h>
+#include <fres_blocks.h>
+#include <fcb.h>
+#include <fra_generic.h>
+#include <frsh_forb.h>
+#include "frsh_resources.h"
+#ifdef CONFIG_ACPI_CPU
+# include <fra_acpi_cpu.h>
+#endif
+#ifdef CONFIG_ACPI_BATTERY
+# include "fra_acpi_battery.h"
+#endif
+#ifdef CONFIG_ACPI_LCD
+# include <fra_acpi_lcd.h>
+#endif
+#include <frsh.h>
+
+static inline int __is_a_valid_power(int level)
+{
+ if (level >= 0 && level < 3 )
+ return 1;
+
+ return 0;
+}
+
+static inline
+fres_block_power_management *__dup_power_management(frsh_contract_t *contract)
+{
+ fres_block_power_management *p, *old_p;
+
+ old_p = fres_contract_get_power_management(*contract);
+ p = malloc(sizeof(*p));
+ if (!p) return 0;
+ /**
+ * Needed since frsh_contract_del_xxx frees the
+ * old block.
+ **/
+ if (old_p)
+ memcpy(p, old_p, sizeof(*old_p));
+ else
+ bzero(p, sizeof(*p));
+
+ return p;
+}
+
+int frsh_contract_set_min_expiration(frsh_contract_t *contract,
+ frsh_rel_time_t min_expiration)
+{
+ fres_block_power_management *p;
+ int ret;
+
+ if (!contract || !*contract)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ p = __dup_power_management(contract);
+ if (!p)
+ return ENOMEM;
+
+ p->min_expiration = min_expiration;
+
+ fres_contract_del_power_management(*contract);
+ ret = fres_contract_add_power_management(*contract, p);
+ if (ret) {
+ free(p);
+ return errno;
+ }
+
+ return FRSH_NO_ERROR;
+}
+
+int frsh_contract_get_min_expiration(const frsh_contract_t *contract,
+ frsh_rel_time_t *min_expiration)
+{
+ fres_block_power_management *p;
+
+ if (!contract || !*contract)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ p = fres_contract_get_power_management(*contract);
+ if (!p)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ *min_expiration = p->min_expiration;
+
+ return FRSH_NO_ERROR;
+}
+
+int frsh_contract_set_min_budget_pow
+ (frsh_contract_t *contract,
+ frsh_power_level_t power_level,
+ const frsh_rel_time_t *pow_min_budget)
+{
+ fres_block_power_management *b;
+ int ret;
+
+ if (!contract || !*contract ||
+ !pow_min_budget)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ b = __dup_power_management(contract);
+ if (!b)
+ return ENOMEM;
+
+ b->min_budget[power_level] = *pow_min_budget;
+
+ fres_contract_del_power_management(*contract);
+ ret = fres_contract_add_power_management(*contract, b);
+ if (ret) {
+ free(b);
+ return errno;
+ }
+
+ return FRSH_NO_ERROR;
+}
+
+int frsh_contract_get_min_budget_pow
+ (const frsh_contract_t *contract,
+ frsh_power_level_t power_level,
+ frsh_rel_time_t *pow_min_budget)
+{
+ fres_block_power_management *b;
+
+ if (!contract || !*contract ||
+ !__is_a_valid_power(power_level))
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ b = fres_contract_get_power_management(*contract);
+ if (!b)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ *pow_min_budget = b->min_budget[power_level];
+
+ return FRSH_NO_ERROR;
+}
+
+int frsh_contract_set_max_budget_pow
+ (frsh_contract_t *contract,
+ frsh_power_level_t power_level,
+ const frsh_rel_time_t *pow_max_budget)
+{
+ fres_block_power_management *b;
+ int ret;
+
+ if (!contract || !*contract ||
+ !pow_max_budget || !__is_a_valid_power(power_level))
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ b = __dup_power_management(contract);
+ if (!b)
+ return ENOMEM;
+
+ b->max_budget[power_level] = *pow_max_budget;
+
+ fres_contract_del_power_management(*contract);
+ ret = fres_contract_add_power_management(*contract, b);
+ if (ret) {
+ free(b);
+ return errno;
+ }
+
+ return FRSH_NO_ERROR;
+}
+
+int frsh_contract_get_max_budget_pow(const frsh_contract_t *contract,
+ frsh_power_level_t power_level,
+ frsh_rel_time_t *pow_max_budget)
+{
+ fres_block_power_management *b;
+
+ if (!contract || !*contract ||
+ !__is_a_valid_power(power_level)) {
+ return FRSH_ERR_BAD_ARGUMENT;
+ }
+
+ b = fres_contract_get_power_management(*contract);
+ if (!b)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ *pow_max_budget = b->max_budget[power_level];
+
+ return FRSH_NO_ERROR;
+}
+
+int frsh_contract_set_utilization_pow
+ (frsh_contract_t *contract,
+ frsh_power_level_t power_level,
+ const frsh_rel_time_t *budget,
+ const frsh_rel_time_t *period,
+ const frsh_rel_time_t *deadline)
+{
+ return FRSH_ERR_NOT_IMPLEMENTED;
+}
+
+int frsh_contract_get_utilization_pow
+ (const frsh_contract_t *contract,
+ frsh_power_level_t power_level,
+ frsh_rel_time_t *budget,
+ frsh_rel_time_t *period,
+ frsh_rel_time_t *deadline)
+{
+ return FRSH_ERR_NOT_IMPLEMENTED;;
+}
+
+/* FIXME: What happens when one application set one power-level and
+ * second application different level. I think this function should
+ * not be part of API. It should be used internally (e.g. by contract
+ * broker) to achieve the requirements specified by
+ * frsh_contract_set_min_expiration() and similar functions.
+ *
+ * This implementation also skips FCB when doing changes to resources,
+ * which is certainly not good, because resource manager does not know
+ * about the change.
+ */
+int frsh_resource_set_power_level
+ (frsh_resource_type_t resource_type,
+ frsh_resource_id_t resource_id,
+ frsh_power_level_t power_level)
+{
+
+ if (!__is_a_valid_power(power_level))
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ switch(resource_type)
+ {
+#ifdef CONFIG_ACPI_CPU
+ case FRSH_RT_PROCESSOR:
+ {
+ int ret;
+ ret = fra_CPU_power_init(resource_id);
+ if (ret) return FRSH_ERR_INTERNAL_ERROR;
+ ret = fra_CPU_set_power(resource_id, power_level);
+ if (ret) return FRSH_ERR_INTERNAL_ERROR;
+
+ /**
+ * @TODO:
+ * if (i budget sono effettivamente diversi)
+ * rinegozia i contratti coi nuovi valori
+ **/
+ break;
+ }
+#endif
+#ifdef CONFIG_ACPI_LCD
+ case FRSH_RT_LCD:
+ {
+ int ret;
+ ret = fra_LCD_power_init(resource_id);
+ if (ret) return FRSH_ERR_INTERNAL_ERROR;
+ ret = fra_LCD_set_power(resource_id, power_level);
+ if (ret) return FRSH_ERR_INTERNAL_ERROR;
+ break;
+ }
+#endif
+ default:
+ return FRSH_ERR_NOT_IMPLEMENTED;
+ }
+
+ return FRSH_NO_ERROR;
+}
+
+int frsh_resource_get_power_level
+ (frsh_resource_type_t resource_type,
+ frsh_resource_id_t resource_id,
+ frsh_power_level_t *power_level)
+{
+ switch(resource_type)
+ {
+#ifdef CONFIG_ACPI_CPU
+ case FRSH_RT_PROCESSOR:
+ {
+ int ret;
+ ret = fra_CPU_get_power(resource_id,
+ (int*) power_level);
+ if (ret) return FRSH_ERR_INTERNAL_ERROR;
+
+ break;
+ }
+#endif
+#ifdef CONFIG_ACPI_LCD
+ case FRSH_RT_LCD:
+ {
+ int ret;
+ ret = fra_LCD_get_power(resource_id,
+ (int*) power_level);
+ if (ret) return FRSH_ERR_INTERNAL_ERROR;
+
+ break;
+ }
+#endif
+ default:
+ return FRSH_ERR_NOT_IMPLEMENTED;
+ }
+
+ return FRSH_NO_ERROR;
+}
+
+int frsh_resource_get_num_power_levels
+ (frsh_resource_type_t resource_type,
+ frsh_resource_id_t resource_id,
+ int *num_power_levels)
+{
+ int ret;
+
+ *num_power_levels = 1;
+
+ switch(resource_type)
+ {
+ case FRSH_RT_PROCESSOR:
+ {
+ ret = fra_CPU_power_init(resource_id);
+ if (ret) goto out;
+
+ break;
+ }
+ case FRSH_RT_LCD:
+ {
+ ret = fra_LCD_power_init(resource_id);
+ if (ret) goto out;
+
+ break;
+ }
+ default:
+ return FRSH_ERR_NOT_IMPLEMENTED;
+ }
+
+ /**
+ * @FIXME:
+ * This looks tremendous... But the number '3' is hardcoded
+ * whereever in the headers as the number of power level, so...
+ */
+ *num_power_levels = 3;
+
+out:
+ return FRSH_NO_ERROR;
+}
+
+int frsh_battery_get_expiration(frsh_abs_time_t *expiration)
+{
+#ifdef CONFIG_ACPI_BATTERY
+ frsh_rel_time_t interval;
+ int ret;
+
+ ret = fra_battery_init();
+ if (ret) return FRSH_ERR_INTERNAL_ERROR;
+
+ ret = fra_battery_expiration(&interval);
+ if (ret == EAGAIN) {
+ *expiration = fosa_msec_to_abs_time(0);
+ goto out;
+ }
+ if (ret)
+ return FRSH_ERR_INTERNAL_ERROR;
+
+ fosa_clock_get_time(FOSA_CLOCK_REALTIME, expiration);
+ *expiration = fosa_abs_time_incr(*expiration, interval);
+
+out:
+ return FRSH_NO_ERROR;
+#else
+ return FRSH_ERR_NOT_IMPLEMENTED;
+#endif
+}
+
/**
* @file frsh_spare_capacity.c
* @author Dario Faggioli <faggioli@gandalf.sssup.it>
+ * @author Michal Sojka <sojkam1@fel.cvut.cz>
*
* @brief Implementation of FRSH contract API on top of FRES contracts.
*
(granularity == FRSH_GR_DISCRETE && utilization_set == NULL))
return FRSH_ERR_BAD_ARGUMENT;
- if (granularity != FRSH_GR_CONTINUOUS)
+ if (granularity != FRSH_GR_CONTINUOUS &&
+ granularity != FRSH_GR_DISCRETE)
return FRSH_ERR_NOT_IMPLEMENTED;
s = malloc(sizeof(*s));
if (!s) return ENOMEM;
+ memset(s, 0, sizeof(*s));
s->budget = *budget_max;
s->period = *period_min;
s->granularity = granularity;
- /*
- * TODO:
- * support utilization-set for discrete spare
- * capacity distribution.
- */
+
+ if (utilization_set) {
+ int i;
+ forb_sequence_alloc_buf(s->variants, utilization_set->size);
+ for (i=0; i<utilization_set->size; i++) {
+ struct fres_container *c = NULL;
+ fres_block_basic *b = NULL;
+ fres_block_timing_reqs *t = NULL;
+ c = fres_container_new();
+ if (!c)
+ goto err;
+ b = malloc(sizeof(*b));
+ if (!b)
+ goto err_ut;
+ t = malloc(sizeof(*t));
+ if (!t)
+ goto err_ut;
+
+ b->budget = utilization_set->utilizations[i].budget;
+ b->period = utilization_set->utilizations[i].period;
+ /* FIXME: workload and contract type should be
+ * the same as in basic_params. The easyest
+ * solution would be to split basic block to
+ * two blocks - (budget, period) and
+ * (workload, contract_type).
+ * Note: frsh_contract_set_reclamation_params()
+ * should be defined differently. */
+ b->workload = FRSH_WT_BOUNDED;
+ b->contract_type = FRSH_CT_REGULAR;
+ ret = fres_container_add_basic(c, b);
+
+ t->d_equals_t = true; /* FIXME: the same as above */
+ t->deadline = utilization_set->utilizations[i].deadline;
+
+ ret = fres_container_add_timing_reqs(c, t);
+
+ forb_sequence_elem(s->variants, i) = c;
+ continue;
+ err_ut:
+ fres_container_destroy(c);
+ free(b); /* FIXME: Possible double free */
+ free(t);
+ goto err;
+ }
+ s->variants._length = utilization_set->size;
+ }
+ /* TODO: In case of CONTINUOUS granularity copy min and max
+ * requirements to the variants. */
s->importance = importance;
s->weight = weight;
s->stability_time = *stability_time;
fres_contract_del_spare_capacity(*contract);
ret = fres_contract_add_spare_capacity(*contract, s);
- if (ret) {
- free(s);
- return errno;
- }
+ if (ret)
+ goto err;
return FRSH_NO_ERROR;
+err:
+ forb_sequence_free_buf(s->variants, forb_no_destructor);
+ free(s);
+ return errno;
}
int frsh_contract_get_reclamation_params
fres_thread_vres_t *th_vres;
int ret = 0;
- th_vres = fra_get_thread_vres(&thread);
+ th_vres = fra_get_thread_vres(&thread, FRSH_RT_PROCESSOR);
if (!th_vres) goto out;
__frsh_synchobj_check_wcet_and_deadline(thread,
fres_thread_vres_t *th_vres;
int ret = 0;
- th_vres = fra_get_thread_vres(&thread);
+ th_vres = fra_get_thread_vres(&thread, FRSH_RT_PROCESSOR);
if (!th_vres) goto out;
__frsh_synchobj_check_wcet_and_deadline(thread,
fres_thread_vres_t *th_vres;
int ret = 0;
- th_vres = fra_get_thread_vres(&thread);
+ th_vres = fra_get_thread_vres(&thread, FRSH_RT_PROCESSOR);
if (!th_vres) goto out;
__frsh_synchobj_check_wcet_and_deadline(thread,
return ret;
}
-int frsh_vresperiod_wait(unsigned long period_num,
- frsh_rel_time_t *next_budget,
- frsh_rel_time_t *next_period,
- bool *was_deadline_missed,
- bool *was_budget_overran)
+int frsh_vresperiod_wait
+ (unsigned long period_num,
+ frsh_rel_time_t *next_budget,
+ frsh_rel_time_t *next_period,
+ bool *was_deadline_missed,
+ bool *was_budget_overran)
{
return FRSH_ERR_NOT_IMPLEMENTED;
}
int frsh_get_period_number(const frsh_vres_id_t vres, long *period_num)
+
{
return FRSH_ERR_NOT_IMPLEMENTED;
}
*
*
*/
+#include <semaphore.h>
+
#include <fres_contract.h>
#include <fres_contract_idl.h>
#include <frsh_core.h>
#include <fres_blocks.h>
#include <string.h>
#include <fcb.h>
-#include "frsh_forb.h"
#include <fra_generic.h>
+#include "frsh_forb.h"
+
+#ifdef CONFIG_AQUOSA
+#include <aqcpu_res.h>
+#endif
+#ifdef CONFIG_CPUCG
+#include <cpucg_res.h>
+#endif
+#ifdef CONFIG_DISKBFQ
+#include <diskbfq_res.h>
+#endif
+
+/**
+ * frsh_thread_bind(), bind a thread to a vres
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_BAD_ARGUMENT(*) (invalid or dummy vres)
+ * FRSH_ERR_NOT_CONTRACTED_VRES(*)
+ * FRSH_ERR_ALREADY_BOUND(*)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ */
+int frsh_thread_bind
+ (const frsh_vres_id_t vres,
+ const frsh_thread_id_t thread)
+{
+ int ret;
+ ret = fra_insert_thread_vres(&thread, vres->allocator->res_type, vres);
+ if (ret) goto err;
+
+ if (vres->allocator->bind_thread) {
+ ret = vres->allocator->bind_thread(vres, thread);
+ } else {
+ ret = FRSH_ERR_NOT_IMPLEMENTED;
+ }
+ if (ret) goto err_delete;
+
+ return FRSH_NO_ERROR;
+
+err_delete:
+ fra_delete_thread_vres(&thread, vres->allocator->res_type);
+err:
+ return FRSH_ERR_INTERNAL_ERROR;
+}
+
+/*
+ * frsh_thread_unbind(), unbind a thread from a vres
+ *
+ * @FIXME:
+ * Notice that, since we don't know from which VRES the
+ * thread should be unbound, we unboind it from all the
+ * ones it is attached to!
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_BAD_ARGUMENT(*) (invalid thread)
+ * FRSH_ERR_NOT_BOUND(*)
+ * FRSH_ERR_INTERNAL_ERROR(*) (something wrong with AQuoSA or with the service thread internal data structures)
+ */
+int frsh_thread_unbind(const frsh_thread_id_t thread)
+{
+ fres_vres_t *vres;
+ int ret;
+
+ /* Unbound from FRSH_RT_PROCESSOR resource (if any) */
+ vres = fra_get_vres_thread_vres(&thread, FRSH_RT_PROCESSOR);
+ if (vres) {
+ if (vres->allocator->unbind_thread) {
+ ret = vres->allocator->unbind_thread(thread);
+ } else {
+ ret = FRSH_ERR_NOT_IMPLEMENTED;
+ }
+ if (ret) goto err;
+
+ ret = fra_delete_thread_vres(&thread, vres->allocator->res_type);
+ if (ret) goto err;
+ }
+
+ /* Unbound from FRSH_RT_DISK resource (if any) */
+ vres = fra_get_vres_thread_vres(&thread, FRSH_RT_DISK);
+ if (vres) {
+ if (vres->allocator->unbind_thread) {
+ ret = vres->allocator->unbind_thread(thread);
+ } else {
+ ret = FRSH_ERR_NOT_IMPLEMENTED;
+ }
+ if (ret) goto err;
+
+ ret = fra_delete_thread_vres(&thread, vres->allocator->res_type);
+ if (ret) goto err;
+ }
+
+ return FRSH_NO_ERROR;
+err:
+ return FRSH_ERR_INTERNAL_ERROR;
+}
+
+/**
+ * structure used to pass the new created thread (or better its wrapper) the
+ * arguments it needs to bind itself to the vres.
+ */
+typedef struct wrapper_pthread_arg {
+ frsh_thread_id_t parent_thread_id;
+ frsh_thread_id_t *thread_id;
+ frsh_thread_code_t pthread_code; /**< function to be running in thread */
+ void *pthread_arg; /**< thread arguments*/
+ frsh_vres_id_t vres;
+ sem_t *stopper; /**< semaphore to synchronize frsh call and wrapper thread */
+ int errcode;
+} wrapper_pthread_arg_t;
+
+/*
+ * typedef struct {
+ * pthread_t pthread_id;
+ * pid_t linux_pid;
+ * pid_t linux_tid;
+ * } FOSA_THREAD_ID_T_OPAQUE;
+ */
+
+/**
+ * Wrapper thread
+ *
+ * possible exit status:
+ * FRSH_ERR_INTENRAL_ERROR (something wrong with threads and signal handling)
+ * FRSH_ERR_TOO_MANY_TASKS(*)
+ * FRSH_ERR_BAD_ARGUMENT(*) (invalid vres)
+ * FRSH_ERR_NOT_CONTRACTED_VRES(*)
+ * whatever the user provided code 'pthread_code' returns
+ */
+static void* wrapper_pthread(void *arg)
+{
+ wrapper_pthread_arg_t* pth = (wrapper_pthread_arg_t*) arg;
+ frsh_thread_id_t* thread_id = pth->thread_id;
+ void *thread_arg = pth->pthread_arg;
+ frsh_thread_code_t thread_code = pth->pthread_code;
+
+ /* bind this thread to vres */
+ *thread_id = fosa_thread_self();
+ pth->errcode = frsh_thread_bind(pth->vres, *thread_id);
+
+ sem_post(pth->stopper);
+ /* No access to pth is allowed after this point, it can vanish already */
+
+ if (pth->errcode) return NULL;
+
+ /* execute thread code */
+ return thread_code(thread_arg);
+}
+
+/*
+ * API call for 'frsh_thread_create_and_bind()', as said prepares the
+ * wrapper code argument data structure, create the new thread and wait
+ * its acknowledgment before stepping over
+ *
+ * possible return values:
+ * FRSH_NO_ERROR
+ * FRSH_ERR_NOT_INITIALIZED
+ * FRSH_ERR_BAD_ARGUMENT (NULL thread or thread_code)
+ * whatever 'fosa_thread_create()' returns
+ * FRSH_ERR_INTERNAL_ERROR
+ */
+int frsh_thread_create_and_bind
+ (const frsh_vres_id_t vres,
+ frsh_thread_id_t *thread,
+ frsh_thread_attr_t *attr,
+ frsh_thread_code_t thread_code,
+ void *arg)
+{
+ wrapper_pthread_arg_t wp_arg;
+ sem_t stopper;
+ int ret;
+
+ sem_init(&stopper, 0, 0);
+
+ if (!thread || !thread_code || !attr)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ wp_arg.parent_thread_id = fosa_thread_self();
+ wp_arg.thread_id = thread;
+ wp_arg.pthread_code = thread_code;
+ wp_arg.pthread_arg = arg;
+ wp_arg.vres = vres;
+ wp_arg.stopper = &stopper;
+
+ /* create the wrapper thread */
+ pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
+ pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM);
+ ret = fosa_thread_create(thread, attr, wrapper_pthread,
+ (void*)&wp_arg);
+
+ if (ret != 0)
+ return(ret);
+
+ sem_wait(&stopper);
+
+ return (wp_arg.errcode);
+}
+
int frsh_thread_create_in_background
(frsh_thread_code_t thread_code,
const void *thread_arg,
{
frsh_contract_t contract;
fosa_rel_time_t zero_msec = fosa_msec_to_rel_time(0);
- int rv = 0;
+ int ret = 0;
/* Background contract creation and negotiation */
frsh_contract_init(&contract);
FRSH_CT_BACKGROUND);
/* It will be accepted: we are asking for 0 budget over 0 period */
- rv = frsh_contract_negotiate(&contract, vres_id);
- if (rv !=0) goto error;
+ ret = frsh_contract_negotiate(&contract, vres_id);
+ if (ret !=0) goto error;
+
+ ret = fosa_thread_create(thread, attr, thread_code, (void*) thread_arg);
+ if (ret != 0) goto error;
- rv = fosa_thread_create(thread, attr, thread_code, (void*) thread_arg);
- if (rv != 0) goto error;
+ ret = fra_insert_thread_vres(thread, FRSH_RT_PROCESSOR, *vres_id);
+ if (ret) goto error;
return 0;
error:
- return rv;
+ return ret;
}
int frsh_thread_get_vres_id
if (!vres_id)
return FRSH_ERR_BAD_ARGUMENT;
- *vres_id = fra_get_vres_thread_vres(&thread);
+ /*
+ * @FIXME:
+ * Why PROCESSOR and not DISK or NETWORK (or whatever) ??
+ */
+ *vres_id = fra_get_vres_thread_vres(&thread,
+ FRSH_RT_PROCESSOR);
return vres_id ? 0 : EINVAL;
}
#include <frsh_core.h>
#include <fra_generic.h>
-#include "frsh_forb.h"
#include <frsh_resources.h>
+#include "frsh_forb.h"
+
+#ifdef CONFIG_AQUOSA
+#include <aqcpu_res.h>
+#endif
+#ifdef CONFIG_CPUCG
+#include <cpucg_res.h>
+#endif
+#ifdef CONFIG_DISKBFQ
+#include <diskbfq_res.h>
+#endif
+
int frsh_vres_get_priority
(frsh_vres_id_t vres_id,
int *priority)
const frsh_resource_id_t resource_id,
frsh_vres_id_t *vres)
{
- return FRSH_ERR_NOT_IMPLEMENTED;
+ fres_block_resource *r;
+ fres_block_label *label;
+
+ if (!contract_label || !vres) {
+ return FRSH_ERR_BAD_ARGUMENT;
+ }
+ r = malloc(sizeof(*r));
+ if (!r) return ENOMEM;
+ r->resource_type = resource_type;
+ r->resource_id = resource_id;
+
+ label = malloc(sizeof(*label));
+ if (!label) {
+ free(r);
+ return ENOMEM;
+ }
+ strncpy(label->label, contract_label, sizeof(label->label));
+ label->label[sizeof(label->label)-1] = '\0';
+
+ *vres = fres_vreses_find_label(label, r);
+ if (*vres) return FRSH_NO_ERROR;
+
+ return FRSH_ERR_CONTRACT_LABEL_UNKNOWN;
}
int frsh_vres_get_renegotiation_status
return 0;
}
+int frsh_vres_get_usage
+ (const frsh_vres_id_t vres,
+ frsh_rel_time_t *spent)
+{
+ if (!vres || !spent) {
+ return FRSH_ERR_BAD_ARGUMENT;
+ }
+ if (vres->allocator->vres_get_usage) {
+ return vres->allocator->vres_get_usage(vres, spent);
+ } else {
+ return FRSH_ERR_NOT_IMPLEMENTED;
+ }
+}
+
+int frsh_vres_get_job_usage
+ (const frsh_vres_id_t vres,
+ frsh_rel_time_t *spent)
+{
+ if (!vres || !spent) {
+ return FRSH_ERR_BAD_ARGUMENT;
+ }
+ if (vres->allocator->vres_get_job_usage) {
+ return vres->allocator->vres_get_job_usage(vres, spent);
+ } else {
+ return FRSH_ERR_NOT_IMPLEMENTED;
+ }
+}
+
+int frsh_vres_get_remaining_budget
+ (const frsh_vres_id_t vres,
+ frsh_rel_time_t *budget)
+{
+ if (!vres || !budget) {
+ return FRSH_ERR_BAD_ARGUMENT;
+ }
+ if (vres->allocator->vres_get_remaining_budget) {
+ return vres->allocator->vres_get_remaining_budget(vres, budget);
+ } else {
+ return FRSH_ERR_NOT_IMPLEMENTED;
+ }
+}
+
test_PROGRAMS += negotiation
negotiation_SOURCES = negotiation.c
+test_PROGRAMS += spare_capacity
+spare_capacity_SOURCES = spare_capacity.c
+
test_PROGRAMS += negobench
negobench_SOURCES = negobench.c
--- /dev/null
+#include <frsh.h>
+#include <error.h>
+#include <res_dummy.h>
+
+#define NUM_CONTRACTS 3
+#define NUM_VARIANTS 3
+
+#define MSEC(x) fosa_msec_to_rel_time(x)
+
+struct contract_data {
+ fosa_rel_time_t stability_time;
+ int importance;
+ int weight;
+ frsh_utilization_t variants[NUM_VARIANTS];
+};
+
+int main(int argc, char *argv[])
+{
+ struct contract_data d[NUM_CONTRACTS] = {
+ { /* Contract 1 */
+ .stability_time = MSEC(0), .importance = 0, .weight = 1,
+ .variants = {
+ { .budget = MSEC(10), .period = MSEC(100), .deadline = MSEC(100) },
+ { .budget = MSEC(20), .period = MSEC(100), .deadline = MSEC(100) },
+ { .budget = MSEC(30), .period = MSEC(100), .deadline = MSEC(100) },
+ }
+ },
+ { /* Contract 2 */
+ .stability_time = MSEC(1000), .importance = 0, .weight = 1,
+ .variants = {
+ { .budget = MSEC(30), .period = MSEC(100), .deadline = MSEC(100) },
+ { .budget = MSEC(30), .period = MSEC( 80), .deadline = MSEC( 80) },
+ { .budget = MSEC(30), .period = MSEC( 60), .deadline = MSEC( 60) },
+ }
+ },
+ { /* Contract 3 */
+ .stability_time = MSEC(10*1000), .importance = 0, .weight = 1,
+ .variants = {
+ { .budget = MSEC(10), .period = MSEC(100), .deadline = MSEC(50) },
+ { .budget = MSEC(20), .period = MSEC( 80), .deadline = MSEC(40) },
+ { .budget = MSEC(30), .period = MSEC( 60), .deadline = MSEC(30) },
+ }
+ },
+ };
+ int ret;
+ frsh_contract_t contract[NUM_CONTRACTS];
+ frsh_vres_id_t vres[NUM_CONTRACTS];
+ frsh_signal_info_t si;
+ int i, j;
+
+ ret = frsh_init();
+ if (ret) PERROR_AND_EXIT(ret, "frsh_init");
+
+ /* Negotiate contracts */
+ for (i=0; i<NUM_CONTRACTS; i++) {
+ ret = frsh_contract_init(&contract[i]);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_init");
+
+ ret = frsh_contract_set_resource_and_label(
+ &contract[i],
+ DUMMY_RESOURCE_TYPE, DUMMY_RESOURCE_ID,
+ NULL);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_resource_and_label");
+
+ ret = frsh_contract_set_basic_params(&contract[i],
+ &d[i].variants[0].budget,
+ &d[i].variants[0].period,
+ FRSH_WT_BOUNDED,
+ FRSH_CT_REGULAR);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_basic_params");
+
+ ret = frsh_contract_set_timing_reqs(&contract[i], false, &d[i].variants[0].deadline,
+ 0, si, 0, si);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_timing_reqs");
+
+ frsh_utilization_set_t utilization_set = { .size = NUM_VARIANTS };
+ for (j=0; j<NUM_VARIANTS; j++)
+ utilization_set.utilizations[j] = d[i].variants[j];
+ ret = frsh_contract_set_reclamation_params(&contract[i],
+ &d[i].stability_time,
+ &d[i].variants[NUM_VARIANTS-1].budget,
+ &d[i].variants[NUM_VARIANTS-1].period,
+ FRSH_GR_DISCRETE,
+ &utilization_set,
+ d[i].importance,
+ d[i].weight);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_reclamation_params");
+
+ char s[1000];
+ memset(s, 0, sizeof(s));
+ fres_contract_to_string(s, sizeof(s), contract[i]);
+ puts(s);
+
+ ret = frsh_contract_negotiate(&contract[i], &vres[i]);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_negotiate");
+ }
+
+ /* Cancel contracts */
+ for (i=0; i<NUM_CONTRACTS; i++) {
+ ret = frsh_contract_cancel(vres[i]);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_cancel");
+ }
+ return 0;
+}
--- /dev/null
+# 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
+
--- /dev/null
+default_CONFIG = CONFIG_ACPI_BATTERY=y
+
+ifeq ($(CONFIG_ACPI_BATTERY),y)
+shared_LIBRARIES = acpi_battery
+
+acpi_battery_SOURCES = fra_acpi_battery.c
+acpi_battery_LIBS += fosa rt acpi
+
+include_HEADERS = fra_acpi_battery.h
+
+SUBDIRS=tests
+endif
--- /dev/null
+/**
+ * @file fres_acpi_cpu.c
+ * @author Dario Faggioli <faggioli@gandalf.sssup.it>
+ * Michael Trimarchi <trimarchimichael@yahoo.it>
+ *
+ * @brief Implementation of shared CPU related ACPI functions.
+ *
+ */
+
+#include "fra_acpi_battery.h"
+
+static global_t acpi_globals;
+
+static int which_batt;
+static battery_t *battery;
+
+static int battery_initialized = 0;
+
+int fra_battery_init()
+{
+ if (battery_initialized == 1) return 0;
+
+ init_acpi_batt(&acpi_globals);
+ init_acpi_acadapt(&acpi_globals);
+
+ battery_initialized = 1;
+
+ return 0;
+}
+
+int fra_battery_expiration(fosa_rel_time_t *expiration)
+{
+ int i, ret;
+ long rmng_msec;
+
+ if (!battery_initialized) return EINVAL;
+
+ read_acpi_acstate(&acpi_globals);
+ if (acpi_globals.adapt.ac_state != P_BATT)
+ return EAGAIN;
+
+ rmng_msec = 0;
+ for (i = 0; i < acpi_globals.batt_count; i++) {
+ ret = read_acpi_batt(i);
+ if (ret == SUCCESS) {
+ rmng_msec +=
+ (long) batteries[i].remaining_time * 60000;
+ }
+ }
+
+ *expiration = fosa_msec_to_rel_time(rmng_msec);
+
+ return 0;
+}
+
--- /dev/null
+#ifndef ACPI_BATTERY
+#define ACPI_BATTERY
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <limits.h>
+#include <string.h>
+#include <libacpi.h>
+
+#include <fosa.h>
+
+int fra_battery_init();
+
+int fra_battery_expiration(fosa_abs_time_t *expiration);
+
+#endif
+
--- /dev/null
+# 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
+
--- /dev/null
+test_PROGRAMS = acpi_battery_test
+acpi_battery_test_SOURCES = acpi_battery_test.c
+LOADLIBES += -L $(AQUOSA_ROOT)/lib -lqreslib -lqsuplib
+#aqcpumngr_LIBS = frm forb contract fosa rt ulut fcb_client
+lib_LOADLIBES += pthread rt frsh qreslib
--- /dev/null
+#include <frsh.h>
+#include <aqcpu_res.h>
+#include <error.h>
+
+int main()
+{
+ int ret;
+ frsh_vres_id_t vres;
+ frsh_contract_t contract;
+ frsh_rel_time_t budget, period;
+ frsh_rel_time_t duration, expiration;
+ unsigned long long duration_msec = 10000;
+
+ 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(10);
+ 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,"TEST_VRES");
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_resource_and_label");
+
+ ret = frsh_contract_set_min_budget_pow(&contract, FRSH_PLT_HIGH, &budget);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_min_budget_pow (FRSH_PLT_HIGH)");
+
+ ret = frsh_contract_set_min_budget_pow(&contract, FRSH_PLT_MEDIUM, &budget);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_min_budget_pow (FRSH_PLT_MEDIUM)");
+
+ ret = frsh_contract_set_min_budget_pow(&contract, FRSH_PLT_LOW, &budget);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_min_budget_pow (FRSH_PLT_LOW)");
+
+ duration = fosa_msec_to_rel_time(duration_msec);
+ ret = frsh_contract_set_min_expiration(&contract, duration);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_min_expiration");
+
+ ret = frsh_contract_get_min_expiration(&contract, &duration);
+ if (ret || fosa_rel_time_to_msec(duration) != duration_msec)
+ PERROR_AND_EXIT(ret, "frsh_contract_get_min_expiration");
+ printf("Minimum duration correctly set to: %lu\n", fosa_rel_time_to_msec(duration));
+
+ ret = frsh_contract_negotiate(&contract, &vres);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_negotiate");
+ printf("Aqcpu vres negotiated, vres-ID: %d\n", (int) vres);
+
+ while (1) {
+ duration_msec += duration_msec;
+ duration = fosa_msec_to_rel_time(duration_msec);
+
+ ret = frsh_contract_set_min_expiration(&contract, duration);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_min_expiration");
+
+ ret = frsh_contract_get_min_expiration(&contract, &duration);
+ if (ret || fosa_rel_time_to_msec(duration) != duration_msec) {
+ //PERROR_AND_EXIT(ret, "frsh_contract_get_duration");
+ printf("%lu %lu\n", fosa_rel_time_to_msec(duration), duration_msec);
+ break;
+ }
+ printf("Minimum duration correctly set to: %lu\n",
+ fosa_rel_time_to_msec(duration));
+
+ ret = frsh_battery_get_expiration(&expiration);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_battery_get_expiration");
+
+ ret = frsh_contract_renegotiate_sync(&contract, vres);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_renegotiate_sync");
+
+ printf("Contract with minimum expiration %lu renegotiated."
+ "System expiration time: %lu\n",
+ fosa_rel_time_to_msec(duration),
+ fosa_abs_time_to_msec(expiration));
+
+ sleep(3);
+ }
+
+ ret = frsh_contract_cancel(vres);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_cancel");
+
+ printf("Test PASSED!\n");
+
+ return 0;
+}
+
--- /dev/null
+CONFIG_AQUOSA=y
+CFLAGS+=-save-temps
+CONFIG_FWP=n
+CONFIG_RESOURCE_DUMMY=n
+CONFIG_RESOURCE_ITEM=n
+CONFIG_RESOURCE_CLUSTER_TREE=n
+
--- /dev/null
+# 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
+
--- /dev/null
+default_CONFIG = CONFIG_ACPI_CPU=y
+
+ifeq ($(CONFIG_ACPI_CPU),y)
+shared_LIBRARIES = acpi_cpu
+
+acpi_cpu_SOURCES = fra_acpi_cpu.c
+acpi_cpu_LIBS += fosa rt m cpufreq
+
+include_HEADERS = fra_acpi_cpu.h
+
+SUBDIRS=tests
+
+endif
--- /dev/null
+/**
+ * @file fres_acpi_cpu.c
+ * @author Dario Faggioli <faggioli@gandalf.sssup.it>
+ * Michael Trimarchi <trimarchimichael@yahoo.it>
+ *
+ * @brief Implementation of shared CPU related ACPI functions.
+ *
+ */
+
+#include "fra_acpi_cpu.h"
+
+static int frequency_initialized = 0;
+
+static unsigned long freqs[3];
+
+int fra_CPU_power_init(int cpu)
+{
+ int ret;
+ int i, j, freq_num = 0;
+ struct cpufreq_available_governors *governors, *g;
+ struct cpufreq_available_frequencies *frequencies, *f;
+
+ if (frequency_initialized == 1) return 0;
+
+ ret = cpufreq_cpu_exists(cpu);
+ if (ret) return EINVAL;
+
+ governors = cpufreq_get_available_governors(cpu);
+ if (!governors) return EINVAL;
+ for (g = governors; g != NULL; g = g->next)
+ if (strncmp("userspace", g->governor, sizeof(*g->governor)) == 0)
+ break;
+ cpufreq_put_available_governors(governors);
+
+ if (g == NULL) return EINVAL;
+
+ ret = cpufreq_modify_policy_governor(cpu, "userspace");
+ if (ret) return EPERM;
+
+
+ frequencies = cpufreq_get_available_frequencies(cpu);
+ if (!frequencies) return EINVAL;
+ for (f = frequencies; f; f = f->next, freq_num++)
+ ;
+
+ f = frequencies;
+ i = j = 0;
+ while (f) {
+ if (i == 0 ||
+ i == ((int)ceil((double)freq_num / 2.0f)) ||
+ i == freq_num - 1) {
+ freqs[j] = f->frequency;
+ j++;
+ }
+ i++;
+ f = f->next;
+ }
+ cpufreq_put_available_frequencies(frequencies);
+
+ frequency_initialized = 1;
+
+ return 0;
+}
+
+int fra_CPU_get_power(int cpu, int *level)
+{
+ unsigned long freq;
+ int i;
+
+ if (!frequency_initialized) return EINVAL;
+
+ freq = cpufreq_get(cpu);
+ for (i = 0; i < 3; i++)
+ if (freqs[i] == freq) {
+ *level = i;
+ return 0;
+ }
+
+ return EINVAL;
+}
+
+int fra_CPU_set_power(int cpu, int level)
+{
+ if (!frequency_initialized ||
+ level >= 3)
+ return EINVAL;
+
+ return cpufreq_set_frequency(cpu, freqs[level]);
+}
+
--- /dev/null
+#ifndef ACPI_CPU
+#define ACPI_CPU
+
+#include <string.h>
+#include <math.h>
+#include <cpufreq.h>
+
+#include <fosa.h>
+
+int fra_CPU_power_init(int cpu);
+
+int fra_CPU_get_power(int cpu, int *level);
+
+int fra_CPU_set_power(int cpu, int level);
+
+#endif
+
--- /dev/null
+# 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
+
--- /dev/null
+test_PROGRAMS = acpi_cpu_test
+acpi_cpu_test_SOURCES = acpi_cpu_test.c
+LOADLIBES += -L $(AQUOSA_ROOT)/lib -lqreslib -lqsuplib
+#aqcpumngr_LIBS = frm forb contract fosa rt ulut fcb_client
+lib_LOADLIBES += pthread rt frsh qreslib
--- /dev/null
+#include <frsh.h>
+#include <error.h>
+
+int main()
+{
+ int power_levels;
+ int ret;
+
+ if (frsh_init())
+ error(1, 0, "FRSH initialization failed\n");
+
+ ret = frsh_resource_get_num_power_levels(FRSH_RT_PROCESSOR,
+ 0, &power_levels);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_resource_get_num_power_levels");
+ printf("Number of power levels suppoerted: %d\n", power_levels);
+
+ if (power_levels == 1)
+ PERROR_AND_EXIT(EINVAL, "Different power levels not supported");
+
+ printf("Starting...\n");
+
+ sleep(3);
+ ret = frsh_resource_set_power_level(FRSH_RT_PROCESSOR,
+ 0, FRSH_PLT_HIGH);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_resource_set_power_level");
+ printf("FRSH_PLT_MEDIUM correctly set\n");
+
+ sleep(3);
+ ret = frsh_resource_set_power_level(FRSH_RT_PROCESSOR,
+ 0, FRSH_PLT_MEDIUM);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_resource_set_power_level");
+ printf("FRSH_PLT_MEDIUM correctly set\n");
+
+ sleep(3);
+ ret = frsh_resource_set_power_level(FRSH_RT_PROCESSOR,
+ 0, FRSH_PLT_LOW);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_resource_set_power_level");
+ printf("FRSH_PLT_LOW correctly set\n");
+
+ return 0;
+}
+
--- /dev/null
+CONFIG_AQUOSA=y
+CFLAGS+=-save-temps
+CONFIG_FWP=n
+CONFIG_RESOURCE_DUMMY=n
+CONFIG_RESOURCE_ITEM=n
+CONFIG_RESOURCE_CLUSTER_TREE=n
+
--- /dev/null
+# 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
+
--- /dev/null
+default_CONFIG = CONFIG_ACPI_LCD=y
+
+ifeq ($(CONFIG_ACPI_LCD),y)
+shared_LIBRARIES = acpi_lcd
+
+acpi_lcd_SOURCES = fra_acpi_lcd.c
+acpi_lcd_LIBS += fosa rt m acpi
+
+include_HEADERS = fra_acpi_lcd.h
+
+SUBDIRS=tests
+endif
+
--- /dev/null
+/**
+ * @file fres_acpi_cpu.c
+ * @author Dario Faggioli <faggioli@gandalf.sssup.it>
+ * Michael Trimarchi <trimarchimichael@yahoo.it>
+ *
+ * @brief Implementation of LCD related ACPI functions.
+ *
+ */
+
+#include "fra_acpi_lcd.h"
+
+static unsigned long bright[3];
+
+static lcd_type_t lcd_initialized = NONE;
+
+static int __parse_proc_brightness(FILE *fd)
+{
+ char buffer[1024];
+ int bright_buf[100], n_bright = 0;
+ char *token, *ptr = buffer;
+
+ if (!fscanf(fd, "levels:%[^\n]", buffer))
+ return -1;
+
+ while ((token = strtok(ptr, " ")) > 0 &&
+ n_bright < 100) {
+ bright_buf[n_bright] = atoi(token);
+
+ ptr = NULL;
+ n_bright++;
+ }
+
+ bright[0] = bright_buf[n_bright];
+ bright[1] = bright_buf[((int)ceil((double)n_bright / 2.0f))];
+ bright[3] = bright_buf[0];
+
+ return 0;
+}
+
+static inline int __setup_lcd_type()
+{
+ int ret = 0;
+ FILE *fd;
+
+ if (lcd_initialized != NONE)
+ return 0;
+
+ fd = fopen(PROC_LCD_PATH_1 "/brightness", "r");
+ if (fd) {
+ ret = __parse_proc_brightness(fd);
+ if (ret) goto end;
+
+ lcd_initialized = PROC_1;
+
+ goto end;
+ }
+
+ fd = fopen(PROC_LCD_PATH_2 "/brightness", "r");
+ if (fd) {
+ ret = __parse_proc_brightness(fd);
+ if (ret) goto end;
+
+ lcd_initialized = PROC_2;
+
+ goto end;
+ }
+
+ fd = fopen(SYS_LCD_PATH_1 "/brightness", "r");
+ if (fd) {
+ /* @TODO: to be done! */
+
+ lcd_initialized = SYS_1;
+
+ goto end;
+ }
+
+ fd = popen("smartdimmer -g", "r");
+ if (fd) {
+ ret = pclose(fd);
+ if (ret) {
+ fprintf(stderr, "Problems using smartdimmer\n");
+ return errno;
+ }
+ bright[0] = 100;
+ bright[1] = 43;
+ bright[3] = 15;
+
+ lcd_initialized = NV;
+
+ goto end;
+ }
+
+ return EINVAL;
+
+end:
+ fclose(fd);
+ return ret;
+}
+
+static int __set_proc_brightness(FILE *fd, int level)
+{
+ int ret;
+
+ ret = fprintf(fd, "%d", bright[level]);
+ if (ret <= 0) {
+ fprintf(stderr,
+ "Could not set brightness level %d\n",
+ level);
+ return errno;
+ }
+
+ return 0;
+}
+
+static int __set_lcd_brightness(int level)
+{
+ FILE *fd;
+ int ret = 0;
+ char str[128];
+
+ if (lcd_initialized == NONE)
+ return EINVAL;
+
+ if (lcd_initialized == PROC_1) {
+ fd = fopen(PROC_LCD_PATH_1 "/brightness", "w");
+ if (!fd)
+ goto err;
+
+ ret = __set_proc_brightness(fd, level);
+ if (ret)
+ return EINVAL;
+ } else if (lcd_initialized == PROC_2) {
+ fd = fopen(PROC_LCD_PATH_2 "/brightness", "w");
+ if (!fd)
+ goto err;
+
+ ret = __set_proc_brightness(fd, level);
+ if (ret)
+ return EINVAL;
+ } else if (lcd_initialized == SYS_1) {
+ /* @TODO: to be done! */
+ } else if (lcd_initialized == NV) {
+ sprintf(str, "smartdimmer -s %lu", bright[level]);
+ fd = popen(str, "r");
+ if (!fd) {
+ fprintf(stderr,
+ "Could not set brightness level %d\n",
+ level);
+ return errno;
+ }
+ }
+
+ fclose(fd);
+err:
+ return ret;
+}
+
+int fra_LCD_power_init(int lcd)
+{
+ return __setup_lcd_type();
+}
+
+int fra_LCD_get_power(int lcd, int *level)
+{
+ /**
+ * @TODO: to be implemented!
+ **/
+ return EINVAL;
+}
+
+int fra_LCD_set_power(int lcd, int level)
+{
+ return __set_lcd_brightness(level);
+}
+
--- /dev/null
+#ifndef ACPI_LCD
+#define ACPI_LCD
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+
+#include <fosa.h>
+
+#define PROC_LCD_PATH_1 "/proc/acpi/video/VID/LCD/"
+#define PROC_LCD_PATH_2 "/proc/acpi/video/VID1/LCD/"
+#define SYS_LCD_PATH_1 "/sys/class/backlight/acpi_video0/"
+
+typedef enum lcd_type {
+ NONE = 0,
+ PROC_1 = 1,
+ PROC_2 = 2,
+ SYS_1 = 3,
+ NV = 4
+} lcd_type_t;
+
+int fra_LCD_power_init(int lcd);
+
+int fra_LCD_get_power(int lcd, int *level);
+
+int fra_LCD_set_power(int lcd, int level);
+
+#endif
+
--- /dev/null
+# 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
+
--- /dev/null
+test_PROGRAMS = acpi_lcd_test
+acpi_lcd_test_SOURCES = acpi_lcd_test.c
+LOADLIBES += -L $(AQUOSA_ROOT)/lib -lqreslib -lqsuplib
+#aqcpumngr_LIBS = frm forb contract fosa rt ulut fcb_client
+lib_LOADLIBES += pthread rt frsh qreslib
--- /dev/null
+#include <frsh.h>
+#include <error.h>
+
+int main()
+{
+ int power_levels;
+ int ret;
+
+ if (frsh_init())
+ error(1, 0, "FRSH initialization failed\n");
+
+ ret = frsh_resource_get_num_power_levels(FRSH_RT_LCD,
+ 0, &power_levels);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_resource_get_num_power_levels");
+ printf("Number of power levels suppoerted: %d\n", power_levels);
+
+ if (power_levels == 1)
+ PERROR_AND_EXIT(EINVAL, "Different power levels not supported");
+
+ printf("Starting...\n");
+
+ sleep(5);
+ ret = frsh_resource_set_power_level(FRSH_RT_LCD,
+ 0, FRSH_PLT_HIGH);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_resource_set_power_level");
+ printf("FRSH_PLT_MEDIUM correctly set\n");
+
+ sleep(5);
+ ret = frsh_resource_set_power_level(FRSH_RT_LCD,
+ 0, FRSH_PLT_MEDIUM);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_resource_set_power_level");
+ printf("FRSH_PLT_MEDIUM correctly set\n");
+
+ sleep(5);
+ ret = frsh_resource_set_power_level(FRSH_RT_LCD,
+ 0, FRSH_PLT_LOW);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_resource_set_power_level");
+ printf("FRSH_PLT_LOW correctly set\n");
+
+ return 0;
+}
+
--- /dev/null
+CONFIG_AQUOSA=y
+CFLAGS+=-save-temps
+CONFIG_FWP=n
+CONFIG_RESOURCE_DUMMY=n
+CONFIG_RESOURCE_ITEM=n
+CONFIG_RESOURCE_CLUSTER_TREE=n
+
{
forb_orb orb;
int ret;
-
- orb = forb_init(&argc, &argv, "frm_cluster_tree");
+ forb_init_attr_t attr = { .orb_id = "org.frescor.frm.cluster_tree" };
+ orb = forb_init(&argc, &argv, &attr);
if (!orb) error(1, errno, "forb_init");
fres_block_register_cluster_tree();
shared_LIBRARIES = frshaqcpu
CFLAGS += -I $(AQUOSA_ROOT)/include
-LOADLIBES += -L $(AQUOSA_ROOT)/lib
-LOADLIBES += -Xlinker -rpath -Xlinker $(AQUOSA_ROOT)/lib
-frshaqcpu_SOURCES += frsh_aqcpu.c aqcpu_contract.c aqcpu_fra.c
+frshaqcpu_SOURCES += aqcpu_contract.c aqcpu_fra.c
include_HEADERS += aqcpu_contract.h aqcpu_res.h
+frshaqcpu_LDFLAGS += -L $(AQUOSA_ROOT)/lib -Xlinker -rpath -Xlinker $(AQUOSA_ROOT)/lib
frshaqcpu_LIBS += qreslib qsuplib
#include <fra_generic.h>
#include "aquosa/qres_lib.h"
+#include "aquosa/qsup_lib.h"
+
#include "aqcpu_contract.h"
UL_LOG_CUST(ulogd_fra_aqcpu);
qres_sid_t sid;
qos_rv rv;
+ if (vres->priv) {
+ errno = -EINVAL;
+ return -1;
+ }
+
/* get aqcpu params from contract */
get_aqcpu_params(vres, &cpu_params);
/* create cpu vres */
/*
* aqcpu_cancel_vres(), cancels vres
*
- * The thread bound to the vres are unbound, and so, detached from their
- * AQuoSA resource reservation servers and continue their execution according
+ * The threads bound to the vres are unbound, and so, detached from their
+ * AQuoSA resource reservation server and continue their execution according
* to the standard Linux scheduler policies.
*
*/
qres_sid_t sid;
qos_rv qrv;
- if (vres->priv) {
+ if (!vres->priv) {
errno = -EINVAL;
return -1;
}
* possible.
*
*/
+static
int aqcpu_change_vres(fres_vres_t *vres, void *priv)
{
aqcpu_params_t cpu_params;
qres_sid_t sid;
qos_rv qrv;
- if (vres->priv) {
+ if (!vres->priv) {
errno = -EINVAL;
return -1;
}
return 0;
}
-static struct fres_allocator aqcpu_allocator = {
- .res_type = FRSH_RT_PROCESSOR,
- .res_id = 0, /* CPU ID 0 */
- .create_vres = aqcpu_create_vres,
- .cancel_vres = aqcpu_cancel_vres,
- .change_vres = aqcpu_change_vres,
- .priv = NULL
-};
-
/*
* installed as an exit handler (with 'atexit()') by the initialization
* code... For now it only calls the cleanup function of the AQuoSA
qres_cleanup();
}
+static
+int aqcpu_fra_exit()
+{
+ qos_rv rv;
+
+ rv = qres_cleanup();
+ return qos_rv_int(rv);
+}
+
+static
+int fra_CPU_bind_thread
+ (fres_vres_t *vres,
+ const fosa_thread_id_t thread)
+{
+ qos_rv qrv;
+ qres_sid_t sid = *((qres_sid_t*)vres->priv);
+
+ if ((qrv = qres_attach_thread(sid, thread.linux_pid,
+ thread.linux_tid)) != QOS_OK)
+ goto err;
+
+ return 0;
+err:
+ return -1;
+}
+
+static
+int fra_CPU_unbind_thread(const fosa_thread_id_t thread)
+{
+ qos_rv qrv;
+ qres_sid_t sid;
+
+ if (qres_get_sid(thread.linux_pid, thread.linux_tid, &sid) != QOS_OK)
+ goto err;
+
+ if ((qrv = qres_detach_thread(sid, thread.linux_pid,
+ thread.linux_tid)) != QOS_OK)
+ goto err;
+
+ return 0;
+err:
+ return -1;
+}
+
+static
+int fra_CPU_get_usage
+ (const fres_vres_t *vres,
+ fosa_rel_time_t *spent)
+{
+ qres_sid_t sid = *((qres_sid_t*)vres->priv);
+ qres_time_t exec_budget;
+ qos_rv rv;
+
+ if (!spent)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ rv = qres_get_exec_time(sid, &exec_budget, NULL);
+ if (rv != QOS_OK) return EINVAL;
+
+ *spent = fosa_usec_to_rel_time(exec_budget);
+
+ return 0;
+}
+
+static
+int fra_CPU_get_job_usage
+ (const fres_vres_t *vres,
+ fosa_rel_time_t *spent)
+{
+ qres_sid_t sid = *((qres_sid_t*)vres->priv);
+ qres_params_t q_params;
+ qres_time_t curr_budget;
+ qos_rv rv;
+
+ if (!spent)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ rv = qres_get_params(sid, &q_params);
+ if (rv != QOS_OK) return EINVAL;
+ rv = qres_get_curr_budget(sid, &curr_budget);
+ if (rv != QOS_OK) return EINVAL;
+
+ *spent = fosa_usec_to_rel_time(q_params.Q - curr_budget);
+
+ return 0;
+}
+
+static
+int fra_CPU_get_remaining_budget
+ (const fres_vres_t *vres,
+ fosa_rel_time_t *budget)
+{
+ qres_sid_t sid = *((qres_sid_t*)vres->priv);
+ qres_time_t curr_budget;
+ qos_rv rv;
+
+ if (!budget)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ rv = qres_get_curr_budget(sid, &curr_budget);
+ if (rv != QOS_OK) return EINVAL;
+
+ *budget = fosa_usec_to_rel_time(curr_budget);
+
+ return 0;
+}
+
+static
+int fra_CPU_set_spare_bandwidth(fres_vres_t *vres)
+{
+ qres_sid_t fake_sid = (qres_sid_t) -1;
+ aqcpu_params_t cpu_params;
+ qos_rv rv;
+
+ /* get aqcpu params from contract */
+ get_aqcpu_params(vres, &cpu_params);
+
+
+ /* reserve CPU bandwidth for feedback */
+ rv = qsup_reserve_spare(r2bw(cpu_params.Q, cpu_params.P));
+ if (rv != QOS_OK) return qos_rv_int(rv);
+
+ printf("Created AQCPU spare (period=%lld us, budget=%lld us)\n",
+ cpu_params.P, cpu_params.Q);
+ if ((vres->priv = malloc(sizeof(qres_sid_t)))) {
+ memcpy(vres->priv, &fake_sid, sizeof(qres_sid_t));
+ }
+
+ return 0;
+}
+
+static
+int fra_CPU_get_desired_budget
+ (fres_vres_t *vres,
+ frsh_rel_time_t *p_budget_out)
+{
+ qres_sid_t sid = *((qres_sid_t*)vres->priv);
+ qres_params_t q_params;
+ qos_rv rv;
+
+ if (!p_budget_out)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ rv = qres_get_params(sid, &q_params);
+ if (rv != QOS_OK) return EINVAL;
+
+ *p_budget_out = fosa_usec_to_rel_time(q_params.Q);
+
+ return 0;
+}
+
+static
+int fra_CPU_set_desired_budget
+ (fres_vres_t *vres,
+ fosa_rel_time_t *p_budget_in)
+{
+ qres_sid_t sid = *((qres_sid_t*)vres->priv);
+ qres_params_t q_params;
+ qos_rv rv;
+
+ if (!p_budget_in)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ rv = qres_get_params(sid, &q_params);
+ if (rv != QOS_OK) return EINVAL;
+
+ q_params.Q = fosa_rel_time_to_usec(*p_budget_in);
+
+ rv = qres_set_params(sid, &q_params);
+ if (rv != QOS_OK) return EINVAL;
+
+ return 0;
+}
+
+static
+int fra_CPU_get_actual_budget
+ (fres_vres_t *vres,
+ fosa_rel_time_t *budget)
+{
+ qres_sid_t sid = *((qres_sid_t*)vres->priv);
+ qres_time_t appr_budget;
+ qos_rv rv;
+
+ if (!budget)
+ return FRSH_ERR_BAD_ARGUMENT;
+
+ rv = qres_get_appr_budget(sid, &appr_budget);
+ if (rv != QOS_OK) return EINVAL;
+
+ *budget = fosa_usec_to_rel_time(appr_budget);
+
+ return 0;
+}
+
+static struct fres_allocator aqcpu_allocator = {
+ .res_type = FRSH_RT_PROCESSOR,
+ .res_id = 0, /* CPU ID 0 */
+ .create_vres = aqcpu_create_vres,
+ .cancel_vres = aqcpu_cancel_vres,
+ .change_vres = aqcpu_change_vres,
+
+ .bind_thread = fra_CPU_bind_thread,
+ .unbind_thread = fra_CPU_unbind_thread,
+
+ .vres_get_usage = fra_CPU_get_usage,
+ .vres_get_job_usage = fra_CPU_get_job_usage,
+ .vres_get_remaining_budget = fra_CPU_get_remaining_budget,
+
+ .set_spare_bandwidth = fra_CPU_set_spare_bandwidth,
+ .get_desired_budget = fra_CPU_get_desired_budget,
+ .set_desired_budget = fra_CPU_set_desired_budget,
+ .get_actual_budget = fra_CPU_get_actual_budget,
+
+ .priv = NULL
+};
+
/*
* aqcpu_fra_init(), initialize FRSH for the calling process
*
if ((qrv = qres_init()) != QOS_OK) {
return -1;
}
-
+
if ((rv = fra_register(&aqcpu_allocator))) {
qres_cleanup();
return rv;
return 0;
}
-
-int aqcpu_fra_exit()
-{
- qos_rv rv;
-
- rv = qres_cleanup();
- return qos_rv_int(rv);
-}
#ifndef AQCPU_RES_H
#define AQCPU_RES_H
+#include <fres_vres.h>
+
#include <forb.h>
#include <fcb.h>
-#include <frsh_core.h>
int aqcpu_fra_init(void);
+++ /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_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>
-#ifndef _XOPEN_SOURCE
-# define _XOPEN_SOURCE 500
-#endif
-#ifndef __USE_UNIX98
-# define __USE_UNIX98
-#endif
-#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 <frsh_time.h>
-
-#include <fres_vres.h>
-#include <fra_generic.h>
-
-/* AQuoSA files */
-#include <aquosa/qres_lib.h>
-#include <aquosa/qsup_lib.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)
-{
- int ret;
- qos_rv qrv;
- qres_sid_t sid = *((qres_sid_t*)vres->priv);
-
- /*if (!aqcpu_is_initialized) {
- return(FRSH_ERR_NOT_INITIALIZED);
- }*/
-
- ret = fra_insert_thread_vres(&thread, vres);
- if (ret) goto err;
-
- if ((qrv = qres_attach_thread(sid, thread.linux_pid,
- thread.linux_tid)) != QOS_OK)
- goto err_delete;
-
- return FRSH_NO_ERROR;
-
-err_delete:
- fra_delete_thread_vres(&thread);
-err:
- return FRSH_ERR_INTERNAL_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)
-{
- int ret;
- qos_rv qrv;
- qres_sid_t sid;
-
- if (qres_get_sid(thread.linux_pid, thread.linux_tid, &sid) != QOS_OK)
- goto err;
-
- ret = fra_delete_thread_vres(&thread);
- if (ret) goto err;
-
- if ((qrv = qres_detach_thread(sid, thread.linux_pid,
- thread.linux_tid)) != QOS_OK)
- goto err;
-
- return FRSH_NO_ERROR;
-err:
- return FRSH_ERR_INTERNAL_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;
- void *thread_arg = pth->pthread_arg;
- frsh_thread_code_t thread_code = pth->pthread_code;
- int errcode;
-
- *thread_id = fosa_thread_self();
- /* bind this thread to vres */
- errcode = frsh_thread_bind(pth->vres, *thread_id);
- pth->errcode = errcode;
-
- sem_post(pth->stopper);
- /* No access to pth is allowed after this point, it can vanish already */
-
- if (errcode) /* vres binding was not successful */
- return NULL;
-
- /* execute thread function */
- return thread_code(thread_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;
-
- 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;
-
- /* 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);
-}
-
-int frsh_vres_get_usage
- (const frsh_vres_id_t vres,
- frsh_rel_time_t *spent)
-{
- qres_sid_t sid = *((qres_sid_t*) vres->priv);
- qres_time_t exec_budget;
- qos_rv rv;
-
- if (!spent)
- return FRSH_ERR_BAD_ARGUMENT;
-
- rv = qres_get_exec_time(sid, &exec_budget, NULL);
- if (rv != QOS_OK) return EINVAL;
-
- *spent = frsh_usec_to_rel_time(exec_budget);
-
- return 0;
-}
-
-int frsh_vres_get_job_usage
- (const frsh_vres_id_t vres,
- frsh_rel_time_t *spent)
-{
- qres_sid_t sid = *((qres_sid_t*) vres->priv);
- qres_params_t q_params;
- qres_time_t curr_budget;
- qos_rv rv;
-
- if (!spent)
- return FRSH_ERR_BAD_ARGUMENT;
-
- rv = qres_get_params(sid, &q_params);
- if (rv != QOS_OK) return EINVAL;
- rv = qres_get_curr_budget(sid, &curr_budget);
- if (rv != QOS_OK) return EINVAL;
-
- *spent = frsh_usec_to_rel_time(q_params.Q - curr_budget);
-
- return 0;
-}
-
-int frsh_vres_get_remaining_budget
- (const frsh_vres_id_t vres,
- frsh_rel_time_t *budget)
-{
- qres_sid_t sid = *((qres_sid_t*) vres->priv);
- qres_time_t curr_budget;
- qos_rv rv;
-
- if (!budget)
- return FRSH_ERR_BAD_ARGUMENT;
-
- rv = qres_get_curr_budget(sid, &curr_budget);
- if (rv != QOS_OK) return EINVAL;
-
- *budget = frsh_usec_to_rel_time(curr_budget);
-
- return 0;
-}
-
-int frsh_feedback_get_spare
- (frsh_contract_t *spare_contract)
-{
- /**
- * TODO:
- * retreive the special feedback contract.
- */
- return FRSH_ERR_NOT_IMPLEMENTED;
-}
-
-int frsh_feedback_set_spare
- (const frsh_contract_t *spare_contract)
-{
- int ret = 0;
- frsh_vres_id_t vres_id;
- fres_block_basic *b;
- qos_rv rv;
-
- if (!spare_contract || !*spare_contract)
- return FRSH_ERR_BAD_ARGUMENT;
-
- ret = frsh_contract_negotiate(spare_contract, &vres_id);
- if (ret) goto err;
-
- b = fres_contract_get_basic(*spare_contract);
- if (!b) return EINVAL;
- rv = qsup_reserve_spare(r2bw(frsh_rel_time_to_usec(b->budget), frsh_rel_time_to_usec(b->period)));
- if (rv != QOS_OK) return EINVAL;
-
-err:
- return ret;
-}
-
-int frsh_feedback_get_desired_budget
- (frsh_vres_id_t vres_id,
- frsh_rel_time_t *p_budget_out)
-{
- qres_sid_t sid = *((qres_sid_t*) vres_id->priv);
- qres_params_t q_params;
- qos_rv rv;
-
- if (!p_budget_out)
- return FRSH_ERR_BAD_ARGUMENT;
-
- rv = qres_get_params(sid, &q_params);
- if (rv != QOS_OK) return EINVAL;
-
- *p_budget_out = frsh_usec_to_rel_time(q_params.Q);
-
- return 0;
-}
-
-int frsh_feedback_set_desired_budget
- (frsh_vres_id_t vres_id,
- frsh_rel_time_t *p_budget_in)
-{
- qres_sid_t sid = *((qres_sid_t*) vres_id->priv);
- qres_params_t q_params;
- qos_rv rv;
-
- if (!p_budget_in)
- return FRSH_ERR_BAD_ARGUMENT;
-
- rv = qres_get_params(sid, &q_params);
- if (rv != QOS_OK) return EINVAL;
-
- q_params.Q = frsh_rel_time_to_usec(*p_budget_in);
-
- rv = qres_set_params(sid, &q_params);
- if (rv != QOS_OK) return EINVAL;
-
- return 0;
-}
-
-int frsh_feedback_get_actual_budget
- (frsh_vres_id_t vres_id,
- frsh_rel_time_t *budget)
-{
- qres_sid_t sid = *((qres_sid_t*) vres_id->priv);
- qres_time_t appr_budget;
- qos_rv rv;
-
- if (!budget)
- return FRSH_ERR_BAD_ARGUMENT;
-
- rv = qres_get_appr_budget(sid, &appr_budget);
- if (rv != QOS_OK) return EINVAL;
-
- *budget = frsh_usec_to_rel_time(appr_budget);
-
- return 0;
-}
-
bin_PROGRAMS = frm_aqcpu
frm_aqcpu_SOURCES = frm_aqcpu.c
LOADLIBES += -L $(AQUOSA_ROOT)/lib -lqreslib -lqsuplib
-frm_aqcpu_LIBS = frm forb contract fosa rt ulut fcb_client
+LOADLIBES += -Xlinker -rpath -Xlinker $(AQUOSA_ROOT)/lib
+frm_aqcpu_LIBS = frm forb contract fosa rt ulut fcb_client qreslib qsuplib
lib_LOADLIBES+= frsh
UL_LOG_CUST(ulogd_frm_aqcpu);
ul_log_domain_t ulogd_fra_fwp = {UL_LOGL_DEB, "frm_aqcpu"};
-static int aqcpu_dummy_admtest(struct fres_sa_scenario *scenario, void *priv,
- bool *schedulable)
+static int aqcpu_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_sa_scenario_for_each_no_cancel_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);
+
ul_logdeb("processing : id=%s, period=%ld ms, budget=%ld ms\n",
- id,
- fosa_rel_time_to_msec(basic->period),
- fosa_rel_time_to_msec(basic->budget));
+ id, period, budget);
+ sum_utilization+= budget*100/period;
}
- *schedulable = scenario->num_contracts <= 3;
+ *schedulable = sum_utilization < 100;
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 = aqcpu_dummy_admtest,
+ .admission_test = aqcpu_admtest,
.priv = NULL
};
{
forb_orb orb;
int ret;
-
- orb = forb_init(&argc, &argv, "frm_aqcpu");
+ forb_init_attr_t attr = { .orb_id = "org.frescor.frm.aqcpu" };
+
+ orb = forb_init(&argc, &argv, &attr);
if (!orb) error(1, errno, "forb_init");
ret = frm_register_and_run(orb, &frm);
aqcputest_SOURCES = aqcputest.c
LOADLIBES += -L $(AQUOSA_ROOT)/lib -lqreslib -lqsuplib
#aqcpumngr_LIBS = frm forb contract fosa rt ulut fcb_client
-lib_LOADLIBES += pthread rt frshaqcpu frsh qreslib
+lib_LOADLIBES += pthread rt frsh qreslib
void* work_thread()
{
- int i;
+ int ret;
+ unsigned long i = 0;
+ frsh_vres_id_t vres_id;
printf("I am alive! \n");
- while(1) {
- printf("I am alive! \n");
+ while(i != 1E9) {
i++;
+ printf("I am alive, run %lu!\n", i);
+
+ ret = frsh_thread_get_vres_id(fosa_thread_self(), &vres_id);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_get_vres_id");
+
+ printf("\tvres retrieved from thread-ID: %d\n", (int) vres_id);
+
+ //ret = frsh_resource_get_vres_from_label("TEST_VRES",
+ // FRSH_RT_PROCESSOR,
+ // 0,
+ // &vres_id);
+ //
+ //if (ret) PERROR_AND_EXIT(ret, "frsh_get_vres_from_label");
+ //
+ //printf("\ton retrived from label: %d\n", (int) vres_id);
}
+ return EXIT_SUCCESS;
}
int main()
frsh_thread_id_t thread;
frsh_contract_t contract;
frsh_rel_time_t budget, period;
+ frsh_rel_time_t zero = fosa_msec_to_rel_time(0);
int ret;
- if (frsh_init()) {
- error(1, 0, "FRSH initialization failed\n");
-
- }
+ if (frsh_init())
+ error(1, errno, "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(10);
- period = fosa_msec_to_rel_time(2000);
+ 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");
+ 0,"TEST_VRES");
if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_resource_and_label");
+ ret = frsh_contract_set_reclamation_params(&contract,
+ &zero,
+ &budget,
+ &period,
+ FRSH_GR_CONTINUOUS,
+ NULL,
+ 0,
+ 0);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_reclamation_params");
+
ret = frsh_contract_negotiate(&contract, &vres);
if (ret) PERROR_AND_EXIT(ret, "frsh_contract_negotiate");
- printf("Aqcpu vres negotiated\n");
+ printf("Aqcpu vres negotiated, vres-ID: %d\n", (int) vres);
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);
+
+ ret = frsh_contract_cancel(vres);
+ if (ret) PERROR_AND_EXIT(ret, "frsh_contract_cancel");
+
printf("Test PASSED!\n");
return 0;
shared_LIBRARIES = frshcpucg
-frshcpucg_SOURCES += frsh_cpucg.c cpucg_contract.c cpucg_fra.c
+frshcpucg_SOURCES += 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)
return 0;
}
+
+
static struct fres_allocator cpucg_allocator = {
.res_type = FRSH_RT_PROCESSOR,
.res_id = 0, /* CPU ID 0 */
{
return 0;
}
+
+int fra_CPU_bind_thread
+ (const fres_vres_t vres,
+ const fosa_thread_id_t thread)
+{
+ struct cgroup* cgroup = (struct cgroup*)vres->priv;
+ struct sched_param param;
+ int p, policy, ret;
+
+ /* if (!aqcpu_is_initialized) {
+ * return(FRSH_ERR_NOT_INITIALIZED);
+ * }
+ */
+
+ pthread_getschedparam(pthread_self(), &policy, ¶m);
+ p = param.sched_priority;
+ printf("policy = %d, priority = %d\n", policy, p);
+ if (p == 0) {
+ param.sched_priority = 1;
+ pthread_setschedparam(pthread_self(), SCHED_RR, ¶m);
+ pthread_getschedparam(pthread_self(), &policy, ¶m);
+ printf("changed policy = %d, changed priority = %d\n",
+ policy, param.sched_priority);
+ }
+
+ if (cgroup_attach_task_pid(cgroup, thread.linux_tid))
+ goto err;
+
+ return 0;
+err:
+ return -1;
+}
+
+int fra_CPU_unbind_thread(const fosa_thread_id_t thread)
+{
+ int ret;
+
+ /* 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 0;
+err:
+ return -1;
+}
+
+int fra_CPU_get_usage
+ (const fres_vres_t vres,
+ fosa_rel_time_t *spent)
+{
+ return -1;
+}
+
+int fra_CPU_get_job_usage
+ (const fres_vres_t vres,
+ fosa_rel_time_t *spent)
+{
+ return -1;
+}
+
+int fra_CPU_get_remaining_budget
+ (const fres_vres_t vres,
+ fosa_rel_time_t *budget)
+{
+ return -1;
+}
+
+int fra_CPU_get_desired_budget
+ (fres_vres_t vres,
+ frsh_rel_time_t *p_budget_out)
+{
+ return -1;
+}
+
+int fra_CPU_set_desired_budget
+ (fres_vres_t vres,
+ fosa_rel_time_t *p_budget_in)
+{
+ return -1;
+}
+
+int fra_CPU_get_actual_budget
+ (fres_vres_t vres,
+ fosa_rel_time_t *budget)
+{
+ return -1;
+}
+
int cpucg_fra_init(void);
+int fra_CPU_bind_thread(fres_vres_t vres, fosa_thread_id_t thread);
+int fra_CPU_unbind_thread(fosa_thread_id_t thread);
+
+int frsh_vres_get_job_usage
+ (const frsh_vres_id_t vres,
+ frsh_rel_time_t *spent)
+{
+ return FRSH_ERR_NOT_IMPLEMENTED;
+}
+
+int fra_CPU_get_usage(const fres_vres_t vres,
+ fosa_rel_time_t *spent);
+int fra_CPU_get_job_usage(const fres_vres_t vres,
+ fosa_rel_time_t *spent)
+int fra_CPU_get_remaining_budget(const fres_vres_t vres,
+ fosa_rel_time_t *budget);
+
+int fra_CPU_get_desired_budget(fres_vres_t vres,
+ frsh_rel_time_t *p_budget_out);
+int fra_CPU_set_desired_budget(fres_vres_t vres,
+ fosa_rel_time_t *p_budget_in);
+int fra_CPU_get_actual_budget(fres_vres_t vres,
+ fosa_rel_time_t *budget);
+
#endif /* CPUCG_RES_H */
+++ /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_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 <fra_generic.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;
- int ret;
-
- /*if (!aqcpu_is_initialized) {
- return(FRSH_ERR_NOT_INITIALIZED);
- }*/
-
- ret = fra_insert_thread_vres(&thread, vres);
- if (ret) goto err;
-
- if (cgroup_attach_task_pid(cgroup, thread.linux_tid)) {
- return FRSH_ERR_INTERNAL_ERROR;
- }
-
- /*sched_getparam(thread.linux_tid, ¶m);
- if (param.sched_priority == 0) {
- param.sched_priority = 1;
- if (sched_setscheduler(thread.linux_tid, SCHED_RR,
- ¶m) == -1) {
- return FRSH_ERR_INTERNAL_ERROR;
- }
- }*/
-
- return FRSH_NO_ERROR;
-err:
- return FRSH_ERR_INTERNAL_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)
-{
- int ret;
- /* 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
-
- ret = fra_delete_thread_vres(&thread);
- if (ret) goto err;
-
- return FRSH_NO_ERROR;
-err:
- return FRSH_ERR_INTERNAL_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;
- void *thread_arg = pth->pthread_arg;
- frsh_thread_code_t thread_code = pth->pthread_code;
- int errcode;
-
- *thread_id = fosa_thread_self();
- /* bind this thread to vres */
- errcode = frsh_thread_bind(pth->vres, *thread_id);
- pth->errcode = errcode;
-
- sem_post(pth->stopper);
- /* No access to pth is allowed after this point, it can vanish already */
-
- if (errcode) /* vres binding was not successful */
- return NULL;
-
- /* execute thread function */
- return thread_code(thread_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 *thread_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 = 0;
- frsh_thread_attr_t updated_attr;
-
- sem_init(&stopper, 0, 0);
-
- if (!thread || !thread_code || !thread_attr)
- return FRSH_ERR_BAD_ARGUMENT;
-
- 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(thread_attr, ¶m);
- p = param.sched_priority;
- printf("priority = %d\n", p);
- if (p == 0) {
- updated_attr = *thread_attr;
- param.sched_priority = 1;
- pthread_attr_setschedparam(&updated_attr, ¶m);
- pthread_attr_getschedparam(&updated_attr, ¶m);
- printf("changed priority = %d\n", param.sched_priority);
- pthread_attr_setinheritsched(&updated_attr, PTHREAD_EXPLICIT_SCHED);
- pthread_attr_setschedpolicy(&updated_attr, SCHED_RR);
- pthread_attr_setscope(&updated_attr, PTHREAD_SCOPE_SYSTEM);
- thread_attr = &updated_attr;
- }
-
- /* create the wrapper thread */
- rv = fosa_thread_create(thread, thread_attr, wrapper_pthread, (void*)&wp);
- if (rv != 0)
- return(rv);
-
- sem_wait(&stopper);
- return (wp.errcode);
-}
-
-int frsh_vres_get_usage
- (const frsh_vres_id_t vres,
- frsh_rel_time_t *spent)
-{
- return FRSH_ERR_NOT_IMPLEMENTED;
-}
-
-int frsh_vres_get_job_usage
- (const frsh_vres_id_t vres,
- frsh_rel_time_t *spent)
-{
- return FRSH_ERR_NOT_IMPLEMENTED;
-}
-
-int frsh_vres_get_remaining_budget
- (const frsh_vres_id_t vres,
- frsh_rel_time_t *budget)
-{
- return FRSH_ERR_NOT_IMPLEMENTED;
-}
-
-int frsh_feedback_get_spare
- (frsh_contract_t *spare_contract)
-{
- return FRSH_ERR_NOT_IMPLEMENTED;
-}
-
-int frsh_feedback_set_spare
- (const frsh_contract_t *spare_contract)
-{
- return FRSH_ERR_NOT_IMPLEMENTED;
-}
-
-int frsh_feedback_get_desired_budget
- (frsh_vres_id_t vres_id,
- frsh_rel_time_t *p_budget_out)
-{
- return FRSH_ERR_NOT_IMPLEMENTED;
-}
-
-int frsh_feedback_set_desired_budget
- (frsh_vres_id_t vres_id,
- frsh_rel_time_t *p_budget_in)
-{
- return FRSH_ERR_NOT_IMPLEMENTED;
-}
-
-int frsh_feedback_get_actual_budget
- (frsh_vres_id_t vres_id,
- frsh_rel_time_t *budget)
-{
- return FRSH_ERR_NOT_IMPLEMENTED;
-}
-
--- /dev/null
+# 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
+
--- /dev/null
+default_CONFIG = CONFIG_DISKBFQ=x
+default_CONFIG = CONFIG_DISKBFQ_SCHED_NAME="bfq"
+default_CONFIG = CONFIG_DISKBFQ_QUEUE_PATH="/sys/class/block/%s/queue/"
+default_CONFIG = CONFIG_DISKBFQ_SCHED_PATH="scheduler"
+default_CONFIG = CONFIG_DISKBFQ_BUDGET_PATH="iosched/budget"
+
+ifeq ($(CONFIG_DISKBFQ),y)
+SUBDIRS = lib mngr #tests
+CFLAGS+= -Wall -Wextra -D_REENTRANT
+endif
--- /dev/null
+Prerequisites
+
+TODO: write down something about BFQ.
+
--- /dev/null
+# 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
+
--- /dev/null
+shared_LIBRARIES = frshdiskbfq
+frshdiskbfq_SOURCES += diskbfq_contract.c diskbfq_fra.c disk_block.c
+include_HEADERS += diskbfq_contract.h diskbfq_res.h res_disk.h
+include_GEN_HEADERS = res_disk_idl.h
+frshdiskbfq_LIBS += fra
+frshdiskbfq_CLIENT_IDL = res_disk_idl.idl
+
--- /dev/null
+/**************************************************************************/
+/* ---------------------------------------------------------------------- */
+/* 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 FRSH (FRescor ScHeduler) */
+/* */
+/* FRSH 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. FRSH 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 FRSH; see file */
+/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
+/* Cambridge, MA 02139, USA. */
+/* */
+/* As a special exception, including FRSH header files in a file, */
+/* instantiating FRSH generics or templates, or linking other files */
+/* with FRSH 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. */
+/**************************************************************************/
+
+/**
+ * @file disk_block.c
+ * @author Dario Faggioli <faggioli@gandalf.sssup.it>
+ *
+ * @brief Description contract blocks specific to dummy resource
+ *
+ *
+ */
+#include <res_disk.h>
+#include <fres_container.h>
+
+static const struct fres_block_desc disk_block_desc = {
+ .name = "disk_sched",
+ .size = sizeof(fres_block_disk_sched),
+ .serialize = (fres_block_serialize_fnc_t*)fres_block_disk_sched_serialize,
+ .deserialize = (fres_block_deserialize_fnc_t*)fres_block_disk_sched_deserialize,
+ .duplicate = fres_block_duplicate_default
+};
+
+int fres_block_register_disk_sched()
+{
+ return fres_block_register(FRES_BLOCK_DISK_SCHED,
+ &disk_block_desc);
+}
+
--- /dev/null
+#include "diskbfq_contract.h"
+
+int get_diskbfq_params(fres_vres_t *vres, diskbfq_params_t *params)
+{
+ fres_block_basic *basic;
+
+ /* get params from contract */
+ basic = fres_contract_get_basic(vres->new);
+
+ params->P = timespec_to_usec(basic->period);
+ params->Q = timespec_to_usec(basic->budget);
+
+ return 0;
+}
+
--- /dev/null
+#ifndef DISKBFQ_CONTRACT_H
+#include <fra_generic.h>
+
+typedef
+struct diskbfq_params_t {
+ long long P;
+ long long Q;
+} diskbfq_params_t;
+
+int get_diskbfq_params(fres_vres_t *vres, diskbfq_params_t *params);
+
+#endif /* DISKBFQ_CONTRACT_H */
--- /dev/null
+/**************************************************************************/
+/* ---------------------------------------------------------------------- */
+/* 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. */
+/**************************************************************************/
+
+/**
+ * @file diskbfq_fra.c
+ * @author Dario Faggiolir <faggioli@gandalf.sssup.it>
+ *
+ * @brief
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <ul_log.h>
+#include <fra_generic.h>
+#include "diskbfq_contract.h"
+#include "res_disk.h"
+
+UL_LOG_CUST(ulogd_fra_cpucg);
+//ul_log_domain_t ulogd_fra_cpucg = {UL_LOGL_MSG, "fra_cpucg"};
+
+static int diskbfq_initialized = 0; /* initialization flag */
+
+/*
+ * Test whether BFQ disk scheduler modue is initialized
+ */
+static inline int diskbfq_is_initialized()
+{
+ return (diskbfq_initialized == 1);
+}
+
+static int diskbfq_create_vres(fres_vres_t *vres, void *priv)
+{
+ fres_block_basic *basic;
+ fres_block_disk_sched *disk_sched;
+ char id[40];
+
+ /*
+ * for disk, reserving the bandwidth does not
+ * make any sense.
+ *
+ * All that we must do is prepare the
+ * vres storing the I/O priority the thread that
+ * will be bound to it will acquire.
+ */
+ fres_contract_id_to_string(id, &vres->id, sizeof(id));
+ basic = fres_contract_get_basic(vres->new);
+ disk_sched = fres_contract_get_disk_sched(vres->new);
+ if (!(vres->priv = malloc(sizeof(int))))
+ return -1;
+
+ memcpy(vres->priv, &disk_sched->ioprio, sizeof(int));
+ printf("Created BFQ VRES (ioprio=%d budget=%ld ms, period=%ld ms)\n",
+ disk_sched->ioprio,
+ fosa_rel_time_to_msec(basic->budget),
+ fosa_rel_time_to_msec(basic->period));
+
+ return 0;
+}
+
+static int diskbfq_cancel_vres(fres_vres_t *vres, void *priv)
+{
+ if (!vres->priv) {
+ errno = -EINVAL;
+ return -1;
+ }
+
+ /*
+ * As before, it is not possible to "free" disk
+ * bandwidth.
+ *
+ * All that we do is free vres memory, the bandwidth
+ * is automatically released when the thread is unbound
+ * from the vres itself.
+ */
+ printf("Canceled DISK VRES (ioprio=%d)\n", *((int*)vres->priv));
+ free(vres->priv);
+
+ return 0;
+}
+
+static
+int diskbfq_change_vres(fres_vres_t *vres, void *priv)
+{
+ fres_block_disk_sched *disk_sched;
+
+ if (!vres->priv) {
+ errno = -EINVAL;
+ return -1;
+ }
+
+ disk_sched = fres_contract_get_disk_sched(vres->new);
+ printf("Changed BFQ VRES from ioprio=%d to ioprio=%d\n",
+ *((int*)vres->priv), (int) disk_sched->ioprio);
+ memcpy(vres->priv, &disk_sched->ioprio, sizeof(int));
+
+ return 0;
+}
+
+int diskbfq_fra_exit()
+{
+ return 0;
+}
+
+static
+int fra_DISK_bind_thread
+ (fres_vres_t *vres,
+ const fosa_thread_id_t thread)
+{
+ fres_block_basic *b;
+ int ret, ioprio = *((int*)vres->priv);
+ struct fres_contract *contract = vres->perceived;
+
+ b = fres_contract_get_basic(contract);
+ if (b->contract_type == FRSH_CT_REGULAR)
+ ioprio = DISKBFQ_IOPRIO_DEFAULT;
+ else if (b->contract_type == FRSH_CT_BACKGROUND)
+ ioprio |= IOPRIO_CLASS_IDLE << IOPRIO_CLASS_SHIFT;
+ else
+ goto err;
+
+ /* ret = ioprio_set(IOPRIO_WHO_PROCESS, gettid(), ioprio); */
+ ret = syscall(__NR_ioprio_set, IOPRIO_WHO_PROCESS,
+ syscall(__NR_gettid), ioprio);
+ if (ret) goto err;
+
+ return 0;
+err:
+ return -1;
+}
+
+static
+int fra_DISK_unbind_thread(const fosa_thread_id_t thread)
+{
+ int ret;
+
+ /* ret = ioprio_set(IOPRIO_WHO_PROCESS, gettid(), IOPRIO_DEFAULT); */
+ ret = syscall(__NR_ioprio_set, IOPRIO_WHO_PROCESS,
+ syscall(__NR_gettid), IOPRIO_PRIO_DEFAULT);
+ if (ret)
+ return -1;
+
+ return 0;
+}
+
+static
+int fra_DISK_get_usage
+ (const fres_vres_t *vres,
+ fosa_rel_time_t *spent)
+{
+ return -1;
+}
+
+static
+int fra_DISK_get_job_usage
+ (const fres_vres_t *vres,
+ fosa_rel_time_t *spent)
+{
+ return -1;
+}
+
+static
+int fra_DISK_get_remaining_budget
+ (const fres_vres_t *vres,
+ fosa_rel_time_t *budget)
+{
+ return -1;
+}
+
+static
+int fra_DISK_set_spare_bandwidth
+ (fres_vres_t *vres)
+{
+ return -1;
+}
+
+static
+int fra_DISK_get_desired_budget
+ (fres_vres_t *vres,
+ frsh_rel_time_t *p_budget_out)
+{
+ return -1;
+}
+
+static
+int fra_DISK_set_desired_budget
+ (fres_vres_t *vres,
+ fosa_rel_time_t *p_budget_in)
+{
+ return -1;
+}
+
+static
+int fra_DISK_get_actual_budget
+ (fres_vres_t *vres,
+ fosa_rel_time_t *budget)
+{
+ return -1;
+}
+
+static struct fres_allocator diskbfq_allocator = {
+ .res_type = FRSH_RT_DISK,
+ .res_id = 0, /* DISK ID 0 */
+ .create_vres = diskbfq_create_vres,
+ .cancel_vres = diskbfq_cancel_vres,
+ .change_vres = diskbfq_change_vres,
+
+ .bind_thread = fra_DISK_bind_thread,
+ .unbind_thread = fra_DISK_unbind_thread,
+
+ .vres_get_usage = fra_DISK_get_usage,
+ .vres_get_job_usage = fra_DISK_get_job_usage,
+ .vres_get_remaining_budget = fra_DISK_get_remaining_budget,
+
+ .set_spare_bandwidth = fra_DISK_set_spare_bandwidth,
+ .get_desired_budget = fra_DISK_get_desired_budget,
+ .set_desired_budget = fra_DISK_set_desired_budget,
+ .get_actual_budget = fra_DISK_get_actual_budget,
+
+ .priv = NULL
+};
+
+/*
+ * diskbfq_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 diskbfq_fra_init(void)
+{
+ if (diskbfq_is_initialized()) {
+ return -1;
+ }
+
+ fres_block_register_disk_sched();
+ if (fra_register(&diskbfq_allocator)) {
+ return -1;
+ }
+
+ diskbfq_initialized = 1;
+ return 0;
+}
+
--- /dev/null
+#ifndef DISKBFQ_RES_H
+#define DISKBFQ_RES_H
+
+#include <forb.h>
+#include <fcb.h>
+#include <frsh_core.h>
+
+int diskbfq_fra_init(void);
+
+int fra_DISK_bind_thread(fres_vres_t *vres, fosa_thread_id_t thread);
+int fra_DISK_unbind_thread(fosa_thread_id_t thread);
+
+int fra_DISK_get_usage(const fres_vres_t *vres,
+ fosa_rel_time_t *spent);
+int fra_DISK_get_job_usage(const fres_vres_t *vres,
+ fosa_rel_time_t *spent);
+int fra_DISK_get_remaining_budget(const fres_vres_t *vres,
+ fosa_rel_time_t *budget);
+
+int fra_DISK_set_spare_bandwidth(fres_vres_t *vres);
+
+int fra_DISK_get_desired_budget(fres_vres_t *vres,
+ frsh_rel_time_t *p_budget_out);
+int fra_DISK_set_desired_budget(fres_vres_t *vres,
+ fosa_rel_time_t *p_budget_in);
+int fra_DISK_get_actual_budget(fres_vres_t *vres,
+ fosa_rel_time_t *budget);
+
+#endif /* DISKBFQ_RES_H */
+
--- /dev/null
+/**************************************************************************/
+/* ---------------------------------------------------------------------- */
+/* 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 FRSH (FRescor ScHeduler) */
+/* */
+/* FRSH 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. FRSH 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 FRSH; see file */
+/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
+/* Cambridge, MA 02139, USA. */
+/* */
+/* As a special exception, including FRSH header files in a file, */
+/* instantiating FRSH generics or templates, or linking other files */
+/* with FRSH 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. */
+/**************************************************************************/
+
+/**
+ * @file res_disk.h
+ * @author Dario Faggioli <faggioli@gandalf.sssup.it>
+ *
+ * @brief Disk resource declarations
+ *
+ *
+ */
+
+#ifndef RES_DISK_H
+#define RES_DISK_H
+
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <sys/syscall.h>
+#include <asm/unistd.h>
+
+#include <forb.h>
+#include <fcb.h>
+#include <res_disk_idl.h>
+#include <fres_contract.h>
+#include <fres_container.h>
+
+enum {
+ IOPRIO_CLASS_NONE,
+ IOPRIO_CLASS_RT,
+ IOPRIO_CLASS_BE,
+ IOPRIO_CLASS_IDLE,
+};
+
+enum {
+ IOPRIO_WHO_PROCESS = 1,
+ IOPRIO_WHO_PGRP,
+ IOPRIO_WHO_USER,
+};
+
+#define IOPRIO_CLASS_SHIFT 13
+/**
+ * @FIXME:
+ * Why all these can't be config parameters?
+ **/
+//#define SYSFS_BFQ_NAME CONFIG_DISKBFQ_SCHED_NAME /* default = "bfq" */
+//#define SYSFS_BFQ_BASIC_PATH CONFIG_DISKBFQ_QUEUE_PATH /* default = "/sys/class/block/%s/queue" */
+//#define SYSFS_BFQ_SCHED_PATH CONFIG_DISKBFQ_QUEUE_PATH CONFIG_DISKBFQ_SCHED_PATH
+//#define SYSFS_BFQ_BUDGET_PATH CONFIG_DISKBFQ_QUEUE_PATH CONFIG_DISKBFQ_BUDGET_PATH /* default = CONFIG_DISKBFQ_QUEUE_PATH "iosched/budget" */
+#define SYSFS_BFQ_NAME "bfq"
+#define SYSFS_BFQ_BASIC_PATH "/sys/block/%s/queue/"
+#define SYSFS_BFQ_SCHED_PATH SYSFS_BFQ_BASIC_PATH "scheduler"
+#define SYSFS_BFQ_BUDGET_PATH SYSFS_BFQ_BASIC_PATH "iosched/max_budget"
+
+#define DISKBFQ_WEIGHT_MAX 100
+
+#define IOPRIO_PRIO_DEFAULT 4
+#define IOPRIO_CLASS_DEFAULT IOPRIO_CLASS_BE
+#define DISKBFQ_IOPRIO_DEFAULT \
+ (IOPRIO_PRIO_DEFAULT || (IOPRIO_CLASS_DEFAULT << IOPRIO_CLASS_SHIFT))
+
+int fra_disk_init(void);
+int fres_block_register_disk_sched(void);
+
+/* Define fres_container_(add|get|del)_disk_sched. */
+FRES_CONTAINER_ACCESSOR(DUMMY_SCHED, disk_sched);
+
+/* Define fres_contract_(add|get|del)_disk_sched. */
+FRES_CONTRACT_ACCESSOR(disk_sched);
+
+#endif
+
--- /dev/null
+////////////////////////////////////////////////////////////////////////////
+// ---------------------------------------------------------------------- //
+// 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. //
+// //
+// //
+// 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 FORB (Frescor Object Request Broker) //
+// //
+// FORB 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. FORB 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 FORB; see file //
+// COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, //
+// Cambridge, MA 02139, USA. //
+// //
+// As a special exception, including FORB header files in a file, //
+// instantiating FORB generics or templates, or linking other files //
+// with FORB 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. //
+////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @file res_disk_idl.idl
+ * @author Dario Faggioli <faggioli@gandalf.sssup.it>
+ *
+ * @brief Contract data block for disk resource
+ *
+ *
+ */
+module fres {
+ module block {
+ struct disk_sched {
+ long weight;
+ long ioprio;
+ };
+ };
+};
--- /dev/null
+# 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
+
--- /dev/null
+
+bin_PROGRAMS = frm_diskbfq
+frm_diskbfq_SOURCES = diskbfq_mngr.c diskbfq_th.c ../lib/disk_block.c
+frm_dummy_CLIENT_IDL = res_disk_idl.idl
+frm_diskbfq_LIBS = frm forb contract fosa m rt ulut fcb_client frshdiskbfq
+
+include_HEADERS = diskbfq_th.h ../lib/res_disk.h
+include_GEN_HEADERS = ../lib/res_disk_idl.h
+
--- /dev/null
+/**************************************************************************/
+/* ---------------------------------------------------------------------- */
+/* 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 BFQ disk bandwidth reservation */
+/* */
+/* 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>
+#include <math.h>
+
+#include "res_disk.h"
+#include "diskbfq_th.h"
+
+UL_LOG_CUST(ulogd_frm_diskbfq);
+ul_log_domain_t ulogd_fra_fwp = {UL_LOGL_DEB, "frm_diskbfq"};
+
+struct disk_data {
+ double throughput;
+ int budget;
+};
+
+static int bandwidth_to_weight(struct disk_data *data,
+ unsigned long budget,
+ unsigned long period)
+{
+ float th, weight;
+ //unsigned long q_i, p_i;
+ int b, w_i;
+
+ th = data->throughput / 10E9;
+ b = data->budget;
+
+ /* Convert to nanoseconds! */
+ //q_i *= 1000;
+ //p_i *= 1000;
+
+ if (period < b / th)
+ return -1;
+
+ weight = (DISKBFQ_WEIGHT_MAX * budget) / (period - (b / th));
+ w_i = floor(weight);
+ if (weight != w_i)
+ w_i++;
+
+ return w_i;
+}
+
+static int weight_to_ioprio(int weight)
+{
+ if (weight >= 100)
+ return 0;
+ if (weight > 14)
+ return 1;
+ if (weight == -1)
+ return -1;
+
+ return 8 - 1 - (weight / 2);
+}
+
+static int diskbfq_admtest(struct fres_sa_scenario *scenario,
+ void *priv,
+ bool *schedulable)
+{
+ struct fres_sa_contract *c;
+ long int period, budget;
+ long int sum_weight = 0;
+ struct disk_data *data = priv;
+
+ fres_sa_scenario_for_each_contract(scenario, c) {
+ fres_block_basic *basic;
+ fres_block_resource *resource;
+ fres_block_disk_sched *disk_sched;
+ char id[40];
+
+ fres_contract_id_to_string(id, &c->contract->id, sizeof(id));
+ basic = fres_contract_get_basic(c->contract);
+ resource = fres_contract_get_resource(c->contract);
+
+ period = fosa_rel_time_to_nsec(basic->period);
+ budget = fosa_rel_time_to_nsec(basic->budget);
+ printf("processing: id=%s, period=%ld ms, budget=%ld ms\n",
+ id, period, budget);
+
+ if (c->contract == c->new) {
+ int ret;
+
+ /* Calc weight and IO prio for the new contracts */
+ disk_sched = malloc(sizeof(*disk_sched));
+ if (!disk_sched) return -1;
+
+ disk_sched->weight = bandwidth_to_weight(data,
+ budget,
+ period);
+ disk_sched->ioprio =
+ weight_to_ioprio(disk_sched->weight);
+ ret = fres_contract_add_disk_sched(c->contract,
+ disk_sched);
+ if (ret) {
+ fprintf(stderr,
+ "Cannot add disk_sched block\n");
+ free(disk_sched);
+ return -1;
+ }
+ } else {
+ disk_sched = fres_contract_get_disk_sched(c->contract);
+ if (!disk_sched) {
+ fprintf(stderr,
+ "disk_sched is not present\n");
+ return -1;
+ }
+ }
+ sum_weight += disk_sched->weight;
+ }
+
+ printf("sum_weight=%ld, max_weight=%d\n",
+ sum_weight,
+ DISKBFQ_WEIGHT_MAX);
+ *schedulable = sum_weight < DISKBFQ_WEIGHT_MAX;
+ printf("=>%s\n", (*schedulable) ? "schedulable" : "not schedulable");
+
+ return 0;
+}
+
+struct disk_data disk;
+
+static struct fres_res_manager frm = {
+ .res_type = FRSH_RT_DISK,
+ .res_id = 0,
+ .admission_test = diskbfq_admtest,
+ .priv = &disk
+};
+
+int main(int argc, char *argv[])
+{
+ forb_init_attr_t attr = { .orb_id = "org.frescor.frm.diskbfq" };
+ forb_orb orb;
+ FILE* fd;
+ int readers = 4;
+ char disk_dev[40], *disk_name = disk_dev;
+ char path[128], scheduler[128];
+ int i, opt, ret;
+
+ if (argc < 3) {
+err_usage:
+ fprintf(stderr, "Usage:\n %s "
+ "-i disk_id -d disk_device [-n readers]\n",
+ argv[0]);
+ error(1, EINVAL, "frm_diskbfq");
+ }
+
+ while ((opt = getopt(argc, argv, "i:d:n:")) != -1) {
+ switch (opt) {
+ case 'i':
+ frm.res_id = atoi(optarg);
+ break;
+ case 'd':
+ strncpy(disk_dev,
+ optarg, sizeof(disk_dev));
+
+ for (i = strlen(disk_dev) - 1; i >= 0; i--) {
+ if (disk_dev[i] == '/') {
+ disk_name = disk_dev + i + 1;
+ break;
+ }
+ }
+ break;
+ case 'n':
+ readers = atoi(optarg);
+ break;
+ default:
+ goto err_usage;
+ }
+ }
+
+ orb = forb_init(&argc, &argv, &attr);
+ if (!orb) error(1, errno, "forb_init");
+
+ /*
+ * Check if BFQ I/O scheduler is available
+ * in the system.
+ */
+ snprintf(path, 128,
+ SYSFS_BFQ_SCHED_PATH,
+ disk_name);
+ if (!(fd = fopen(path, "rw")))
+ error(1, errno, "frm_generic_run");
+
+ ret = fscanf(fd, "%128[^\n]", scheduler);
+ if (ret == 0 || ret == EOF)
+ error(1, errno, "frm_generic_run");
+ if (!strstr(scheduler, SYSFS_BFQ_NAME))
+ error(1, errno, "frm_generic_run");
+
+ /**
+ * Now check if BFQ is the default I/O scheduler
+ * for the specific disk and set it to so if not.
+ **/
+ else if (!strstr(scheduler, "[" SYSFS_BFQ_NAME "]")) {
+ rewind(fd);
+ ret = fprintf(fd, SYSFS_BFQ_NAME);
+ if (ret && ret != EOF)
+ ret = fflush(fd);
+ if (ret == 0 || ret == EOF)
+ error(1, errno, "frm_generic_run");
+ }
+ fclose(fd);
+
+ snprintf(path, sizeof(path),
+ SYSFS_BFQ_BUDGET_PATH,
+ disk_name);
+ if (!(fd = fopen(path, "r")))
+ error(1, errno, "frm_generic_run");
+
+ ret = fscanf(fd, "%d", &disk.budget);
+ if (ret == 0 || ret == EOF)
+ error(1, errno, "frm_generic_run");
+ fclose(fd);
+
+ /**
+ * Estimate the disk throughput in order to achieve
+ * effective weight assignement during runtime.
+ **/
+ disk.throughput = estimate_throughput(disk_dev, readers);
+ if (disk.throughput < 0.0)
+ error(1, errno, "frm_generic_run");
+
+ fprintf(stdout, "disk name: %s\n"
+ "scheduler: %s\n"
+ "disk aggregate throughput: %f\n"
+ "scheduling budget: %d\n",
+ disk_name, SYSFS_BFQ_NAME, disk.throughput, disk.budget);
+
+ /* Register fres_block_disk_sched to contract handling
+ * functions */
+ fres_block_register_disk_sched();
+
+ ret = frm_register_and_run(orb, &frm);
+ if (ret) error(1, errno, "frm_generic_run");
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * The only function of interest is:
+ * double estimate_throughput(char *device, int streamers);
+ * @device: the device we want to test.
+ * @streamers: the number of sequential readers we're interested in.
+ */
+
+#include <diskbfq_th.h>
+
+/* given a device name, return its size in sectors */
+static int64_t read_size(char *device)
+{
+ int count, size, i;
+ int64_t rval;
+ char *path, *devname = device;
+ FILE *fp;
+
+ for (i = strlen(device) - 1; i >= 0; i--) {
+ if (device[i] == '/') {
+ devname = device + i + 1;
+ break;
+ }
+ }
+
+ size = sizeof(SYSFS_BASE) + strlen(devname) + sizeof("/size");
+ path = calloc(1, size);
+ if (!path)
+ return -ENOMEM;
+
+ snprintf(path, size, SYSFS_BASE "%s/size", devname);
+ fp = fopen(path, "r");
+ if (!fp) {
+ rval = -ENODEV;
+ goto err;
+ }
+
+ count = fscanf(fp, "%llu", (unsigned long long*) &rval);
+ if (count != 1)
+ rval = -EIO;
+
+ fclose(fp);
+err:
+ free(path);
+ return rval;
+}
+
+/* reader: reads from the device until stop_all becomes true */
+static void *reader_body(void *arg)
+{
+ struct reader_data *rdata = arg;
+ off_t offset = rdata->offset * 512;
+ char buffer[2 * READ_BLKSIZE], *bufptr;
+ ssize_t count;
+ int page_size;
+
+ /* O_DIRECT needs page-aligned buffer/offset/blksize */
+ page_size = sysconf(_SC_PAGESIZE);
+ bufptr = (char *)(((uintptr_t)buffer + page_size) & ~(page_size - 1));
+
+ while (!*rdata->stop) {
+ /* offset may lose alignment if a read ends prematurely */
+ offset = (offset + page_size) & ~(page_size - 1);
+
+ /* should not happen, wrap if we're too fast */
+ if (offset > READ_ROOM * 512 - READ_BLKSIZE)
+ offset = rdata->offset * 512;
+
+ /* use pread() to share devfd among all the threads */
+ count = pread(rdata->devfd, bufptr, READ_BLKSIZE, offset);
+ if (count < 0) {
+ rdata->error = errno;
+ break;
+ }
+ rdata->completed += count / 512;
+ offset += count;
+ }
+
+ dprintf("reader: completed = %lld, error = %d\n",
+ rdata->completed, rdata->error);
+ return NULL;
+}
+
+/* wait for the termination of all the readers (collecting errors, if any) */
+static void wait_all(struct dprof_data *ddata, int *error)
+{
+ struct reader_data *rdata;
+ int i;
+
+ ddata->stop_all = 1;
+ for (i = 0; i < ddata->streamers; i++) {
+ rdata = ddata->reader_data + i;
+ if (!rdata->started)
+ continue;
+ pthread_join(rdata->id, NULL);
+ if (rdata->error && error)
+ *error = rdata->error;
+ }
+}
+
+/* create and start all the readers */
+static struct dprof_data *create_readers(int streamers, int devfd,
+ int64_t devsize)
+{
+ struct dprof_data *ddata;
+ struct reader_data *rdata;
+ int i, error = 0;
+ off_t step;
+
+ ddata = calloc(1, sizeof(struct reader_data) * streamers +
+ sizeof(struct dprof_data));
+ if (!ddata)
+ return NULL;
+
+ ddata->streamers = streamers;
+
+ /* space the readers evenly over the disk surface */
+ step = (devsize - streamers * READ_ROOM) / streamers;
+
+ for (i = 0; i < streamers; i++) {
+ rdata = ddata->reader_data + i;
+ rdata->offset = step * i;
+ rdata->stop = &ddata->stop_all;
+ rdata->devfd = devfd;
+
+ error = pthread_create(&rdata->id, NULL, reader_body, rdata);
+ if (error) {
+ wait_all(ddata, NULL);
+ free(ddata);
+ return NULL;
+ }
+ rdata->started = 1;
+ }
+
+ return ddata;
+}
+
+/* return the throughput, in KiB/s */
+static double calc_throughput(struct dprof_data *ddata,
+ struct timeval *begin,
+ struct timeval *end)
+{
+ struct reader_data *rdata;
+ double total = 0, delta;
+ int i;
+
+ for (i = 0; i < ddata->streamers; i++) {
+ rdata = ddata->reader_data + i;
+ total += rdata->completed;
+ }
+
+ delta = end->tv_usec - begin->tv_usec;
+ delta += (end->tv_sec - begin->tv_sec) * 1000000.0;
+
+ /* total is in sectors, delta in usecs, convert to KiB/s */
+ return total / delta * (512 * 1000000 / 1024);
+}
+
+double estimate_throughput(char *device, int streamers)
+{
+ struct timeval begin, end;
+ struct dprof_data *ddata;
+ double throughput = -1;
+ int64_t devsize;
+ int devfd, error = 0;
+
+ /* get device size */
+ devsize = read_size(device);
+ if (devsize < 0)
+ return -1;
+
+ /* open the device */
+ devfd = open(device, O_RDONLY | O_DIRECT);
+ if (devfd < 0)
+ return -1;
+
+ /* let the good times roll... */
+ gettimeofday(&begin, NULL);
+
+ /* start all the threads */
+ ddata = create_readers(streamers, devfd, devsize);
+ if (!ddata)
+ goto err;
+
+ /* let them read */
+ sleep(MEAS_INTERVAL);
+
+ /* wait for their completion */
+ wait_all(ddata, &error);
+
+ /* this is the end... */
+ gettimeofday(&end, NULL);
+
+ if (!error)
+ throughput = calc_throughput(ddata, &begin, &end);
+ free(ddata);
+
+err:
+ close(devfd);
+
+ return throughput;
+}
+
--- /dev/null
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE < 500)
+#define _XOPEN_SOURCE 500
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#ifdef CONFIG_DISKBFQ_DEBUG
+#define dprintf(fmt...) printf(fmt)
+#else
+#define dprintf(fmt...)
+#endif
+
+/* reserve 1GiB per client */
+#define READ_ROOM (2048ULL * 1024)
+
+/* read 512KiB per transaction */
+#define READ_BLKSIZE (1024ULL * 512)
+
+/* (max) 5 seconds */
+#define MEAS_INTERVAL 5
+
+#define SYSFS_BASE "/sys/block/"
+#define DROP_CACHES "/proc/sys/vm/drop_caches"
+
+/* per-reader descriptor */
+struct reader_data {
+ pthread_t id;
+ size_t completed;
+ off_t offset;
+ int devfd;
+ int started;
+ int error;
+ volatile int *stop;
+};
+
+/* global state, malloc'd to allow estimate_througput() to be reentrant */
+struct dprof_data {
+ int streamers;
+ volatile int stop_all;
+ struct reader_data reader_data[];
+};
+
+double estimate_throughput(char *device, int streamers);
+
--- /dev/null
+# 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
+
--- /dev/null
+test_PROGRAMS = cpucgtest
+cpucgtest_SOURCES = cpucgtest.c
+#aqcpumngr_LIBS = frm forb contract fosa rt ulut fcb_client
+lib_LOADLIBES += pthread rt frshcpucg frsh
--- /dev/null
+CONFIG_DISKBFQ=y
+CFLAGS+=-save-temps
+CONFIG_FWP=n
+CONFIG_RESOURCE_DUMMY=n
+CONFIG_RESOURCE_ITEM=n
+CONFIG_RESOURCE_CLUSTER_TREE=n
+
--- /dev/null
+#include <frsh.h>
+#include <diskbfq_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_DISK,
+ 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("Disk (BFQ) 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;
+}
+
{
forb_orb orb;
int ret;
-
- orb = forb_init(&argc, &argv, "frm_dummy");
+ forb_init_attr_t attr = { .orb_id = "org.frescor.frm.dummy" };
+ orb = forb_init(&argc, &argv, &attr);
if (!orb) error(1, errno, "forb_init");
/* Register fres_block_dummy_sched to contract handling
{
forb_orb orb;
int ret;
-
- orb = forb_init(&argc, &argv, "frm_fpga");
+ forb_init_attr_t attr = { .orb_id = "org.frescor.frm.fpga" };
+ orb = forb_init(&argc, &argv, &attr);
if (!orb) error(1, errno, "forb_init");
/* Register fres_block_fpga to contract handling
char platform[]="telosb";
char *parametrsITEM[] ={NULL,device,platform};
-
- orb = forb_init(&argc, &argv, "frm_item");
+ forb_init_attr_t attr = { .orb_id = "org.frescor.frm.item" };
+ orb = forb_init(&argc, &argv, &attr);
if (!orb) error(1, errno, "forb_init");