//=====================================================================
// FFFFFFIII RRRRR SSTTTTTTT
// FF IIR RR SS
// FF IR SS
// FFFFFF RRRR SSSSST
// FF FI RRR SS
// FF II RRR SS
// FF IIIIIR RS
//
// Basic FSF(FIRST Scheduling Framework) contract management
// S.Ha.R.K. Implementation
//=====================================================================
#include "fsf_contract.h"
#include "fsf_server.h"
#include <kernel/descr.h>
#include <kernel/func.h>
#include <pistar.h>
struct hash_entry
{
mutex_t mx
;
int id
;
};
#define MAX_HASH_ENTRY FSF_MAX_SHARED_OPERATION
struct hash_entry htable
[MAX_HASH_ENTRY
];
/*----------------------------------------------------------------------*/
/* hash_fun() : address hash table */
/*----------------------------------------------------------------------*/
static int hash_fun
(fsf_shared_obj_id_t
*id
)
{
return (*id
% MAX_HASH_ENTRY
);
}
void fsf_register_shared_object
(void) {
int i
=0;
// Init Hash table
//kern_printf("(IT SO)\n");
for (i
=0; i
<MAX_HASH_ENTRY
; i
++) {
htable
[i
].
id=-1;
}
}
int fsf_initialize_contract
(fsf_contract_parameters_t
*contract
)
{
struct timespec default_deadline
= FSF_DEFAULT_DEADLINE
;
/* Check */
if (!contract
) return FSF_ERR_NOT_INITIALIZED
;
/* Set to default value */
NULL_TIMESPEC
(&contract
->budget_min
);
NULL_TIMESPEC
(&contract
->budget_max
);
NULL_TIMESPEC
(&contract
->period_min
);
NULL_TIMESPEC
(&contract
->period_max
);
contract
->workload
= FSF_DEFAULT_WORKLOAD
;
contract
->local_scheduler_id
= FSF_DEFAULT_SCHEDULER
;
contract
->d_equals_t
= FSF_DEFAULT_D_EQUALS_T
;
TIMESPEC_ASSIGN
(&contract
->deadline
,&default_deadline
);
contract
->budget_overrun_sig_notify
= 0;
memset(&contract
->budget_overrun_sig_value
,0,sizeof(union sigval
));
contract
->deadline_miss_sig_notify
= 0;
memset(&contract
->deadline_miss_sig_value
,0,sizeof(union sigval
));
contract
->granularity
= FSF_DEFAULT_GRANULARITY
;
contract
->utilization_set.
size = 0;
contract
->quality
= FSF_DEFAULT_QUALITY
;
contract
->importance
= FSF_DEFAULT_IMPORTANCE
;
contract
->preemption_level
= 0;
contract
->critical_sections.
size = 0;
return 0;
}
int fsf_set_contract_basic_parameters
(fsf_contract_parameters_t
*contract
,
const struct timespec
*budget_min
,
const struct timespec
*period_max
,
const struct timespec
*budget_max
,
const struct timespec
*period_min
,
fsf_workload_t workload
)
{
if (!contract
) return FSF_ERR_NOT_INITIALIZED
;
if (budget_min
) TIMESPEC_ASSIGN
(&contract
->budget_min
,budget_min
);
if (period_max
) TIMESPEC_ASSIGN
(&contract
->period_max
,period_max
);
if (budget_max
) TIMESPEC_ASSIGN
(&contract
->budget_max
,budget_max
);
if (period_min
) TIMESPEC_ASSIGN
(&contract
->period_min
,period_min
);
contract
->workload
= workload
;
return 0;
}
int fsf_get_contract_basic_parameters
(const fsf_contract_parameters_t
*contract
,
struct timespec
*budget_min
,
struct timespec
*period_max
,
struct timespec
*budget_max
,
struct timespec
*period_min
,
fsf_workload_t
*workload
)
{
if (!contract
) return FSF_ERR_NOT_INITIALIZED
;
TIMESPEC_ASSIGN
(budget_min
,&contract
->budget_min
);
TIMESPEC_ASSIGN
(period_max
,&contract
->period_max
);
TIMESPEC_ASSIGN
(budget_max
,&contract
->budget_max
);
TIMESPEC_ASSIGN
(period_min
,&contract
->period_min
);
*workload
= contract
->workload
;
return 0;
}
int fsf_set_contract_timing_requirements
(fsf_contract_parameters_t
*contract
,
bool d_equals_t
,
const struct timespec
*deadline
,
int budget_overrun_sig_notify
,
union sigval budget_overrun_sig_value
,
int deadline_miss_sig_notify
,
union sigval deadline_miss_sig_value
)
{
if (!contract
) return FSF_ERR_NOT_INITIALIZED
;
contract
->d_equals_t
= d_equals_t
;
if (deadline
) TIMESPEC_ASSIGN
(&contract
->deadline
,deadline
);
contract
->budget_overrun_sig_notify
= budget_overrun_sig_notify
;
contract
->budget_overrun_sig_value
= budget_overrun_sig_value
;
contract
->deadline_miss_sig_notify
= deadline_miss_sig_notify
;
contract
->deadline_miss_sig_value
= deadline_miss_sig_value
;
return 0;
}
int fsf_get_contract_timing_requirements
(const fsf_contract_parameters_t
*contract
,
bool
*d_equals_t
,
struct timespec
*deadline
,
int *budget_overrun_sig_notify
,
union sigval
*budget_overrun_sig_value
,
int *deadline_miss_sig_notify
,
union sigval
*deadline_miss_sig_value
)
{
if (!contract
) return FSF_ERR_NOT_INITIALIZED
;
*d_equals_t
= contract
->d_equals_t
;
TIMESPEC_ASSIGN
(deadline
,&contract
->deadline
);
*budget_overrun_sig_notify
= contract
->budget_overrun_sig_notify
;
*budget_overrun_sig_value
= contract
->budget_overrun_sig_value
;
*deadline_miss_sig_notify
= contract
->deadline_miss_sig_notify
;
*deadline_miss_sig_value
= contract
->deadline_miss_sig_value
;
return 0;
}
int fsf_set_contract_reclamation_parameters
(fsf_contract_parameters_t
*contract
,
fsf_granularity_t granularity
,
const fsf_utilization_set_t
*utilization_set
,
int quality
,
int importance
)
{
if (!contract
) return FSF_ERR_NOT_INITIALIZED
;
contract
->granularity
= granularity
;
if (utilization_set
) memcpy(&contract
->utilization_set
,utilization_set
,sizeof(fsf_utilization_set_t
));
contract
->quality
= quality
;
contract
->importance
= importance
;
return 0;
}
int fsf_get_contract_reclamation_parameters
(const fsf_contract_parameters_t
*contract
,
fsf_granularity_t
*granularity
,
fsf_utilization_set_t
*utilization_set
,
int *quality
,
int *importance
)
{
if (!contract
) return FSF_ERR_NOT_INITIALIZED
;
*granularity
= contract
->granularity
;
memcpy(utilization_set
,&contract
->utilization_set
,sizeof(fsf_utilization_set_t
));
*quality
= contract
->quality
;
*importance
= contract
->importance
;
return 0;
}
/* OLD VERSION
int fsf_set_contract_synchronization_parameters
(fsf_contract_parameters_t *contract,
fsf_preemption_level_t preemption_level,
const fsf_critical_sections_t *critical_sections)
{
if (!contract) return FSF_ERR_NOT_INITIALIZED;
contract->preemption_level = preemption_level;
if (critical_sections) memcpy(&contract->critical_sections,critical_sections,sizeof(fsf_critical_sections_t));
return 0;
}
*/
int
fsf_get_contract_synchronization_parameters
(const fsf_contract_parameters_t
*contract
,
fsf_preemption_level_t
*preemption_level
,
fsf_critical_sections_t
*critical_sections
)
{
if (!contract
) return FSF_ERR_NOT_INITIALIZED
;
*preemption_level
= contract
->preemption_level
;
memcpy(critical_sections
,&contract
->critical_sections
,sizeof(fsf_critical_sections_t
));
return 0;
}
int
fsf_set_local_scheduler_parameter
(fsf_contract_parameters_t
*contract
,
fsf_scheduler_id_t local_scheduler_id
)
{
if (!contract
) return FSF_ERR_NOT_INITIALIZED
;
contract
->local_scheduler_id
= local_scheduler_id
;
return 0;
}
int
fsf_get_local_scheduler_parameter
(const fsf_contract_parameters_t
*contract
,
fsf_scheduler_id_t
*local_scheduler_id
)
{
if (!contract
) return FSF_ERR_NOT_INITIALIZED
;
*local_scheduler_id
= contract
->local_scheduler_id
;
return 0;
}
// mutex lock function
int fsf_lock_object
(fsf_shared_operation_t
*op
) {
int index
, oldindex
;
index
=hash_fun
(&(op
->obj_id
));
//kern_printf("index %d, htableid %d, obj_op_id %d", index, htable[index].id,op->obj_id);
if (htable
[index
].
id!=op
->obj_id
) {
oldindex
=index
;
index
= (index
+ 1) % MAX_HASH_ENTRY
;
// find
while (htable
[index
].
id != op
->obj_id
&& index
!=oldindex
) index
=(index
+1) % MAX_HASH_ENTRY
;
if (index
==oldindex
) return -1;
}
//kern_printf("(SO LK)");
// we need a special implementation for mutex_lock ... additional parameter
return PISTAR_lock
(FSF_get_shared_object_level
(), &htable
[index
].
mx,TIMESPEC2USEC
(&op
->wcet
));
}
int fsf_unlock_object
(fsf_shared_operation_t
*op
) {
int index
, oldindex
;
index
=hash_fun
(&op
->obj_id
);
if (htable
[index
].
id!=op
->obj_id
) {
oldindex
=index
;
index
= (index
+ 1) % MAX_HASH_ENTRY
;
// find
while (htable
[index
].
id != op
->obj_id
&& index
!=oldindex
) index
=(index
+1) % MAX_HASH_ENTRY
;
if (index
==oldindex
) return -1;
}
//kern_printf("UNLOCK index %d", index);
return mutex_unlock
(&htable
[index
].
mx);
}
int fsf_init_shared_object
(fsf_shared_object_t
*obj
,
fsf_shared_obj_id_t id
) {
int index
;
int oldindex
;
PISTAR_mutexattr_t a
;
SYS_FLAGS f
;
PISTAR_mutexattr_default
(a
);
//kern_printf("(SI SO)\n");
f
=kern_fsave
();
index
=hash_fun
(&id
);
//kern_printf("Index %d Hash %d", index, htable[index].id);
if (htable
[index
].
id == id
) {
kern_frestore
(f
);
return -1;
}
if (htable
[index
].
id>=0) {
oldindex
=index
;
index
= (index
+ 1) % MAX_HASH_ENTRY
;
// collision detection
while (htable
[index
].
id >=0 && index
!=oldindex
) index
=(index
+1) % MAX_HASH_ENTRY
;
// table is full
if (index
==oldindex
) {
kern_frestore
(f
);
return -1;
}
}
obj
->size
=0;
mutex_init
(&(htable
[index
]).
mx, &a
);
htable
[index
].
id=id
;
obj
->obj_id
=id
;
kern_frestore
(f
);
return 0;
//kern_printf("(EI SO)\n");
}
// Declare an operation
// This function is used to declare that a shared object has
// a synchronized operation on it.
// It checks if another operation with the same id has already been
// declared; if so, return false (-1).
// The obj_id field of the operation is set equal to the shared object id.
// the structure op is copied in the first free element in the array
// shared_op pof the structure obj. If there are no more free element,
// returns -1.
// Returns 0 if the operation has been completed, -1 otherwise.
int fsf_declare_shared_object_operation
(fsf_shared_object_t
*obj
,
fsf_shared_operation_t
*op
) {
int i
;
SYS_FLAGS f
;
f
=kern_fsave
();
for (i
=0; i
<obj
->size
; i
++) {
// fail if the operation already declared
if (op
->op_id
==obj
->shared_op
[i
].
op_id) {
kern_frestore
(f
);
return -1;
}
}
// fail if the object is full
if (obj
->size
>(FSF_MAX_SHARED_OPERATION
-1)) {
kern_frestore
(f
);
return -1;
}
//kern_printf("(DO SO)");
obj
->size
++;
obj
->shared_op
[i
].
op_id = op
->op_id
;
TIMESPEC_ASSIGN
(&obj
->shared_op
[i
].
wcet,&op
->wcet
);
obj
->shared_op
[i
].
obj_id = obj
->obj_id
;
op
->obj_id
= obj
->obj_id
;
kern_frestore
(f
);
return 0;
}
int fsf_set_contract_synchronization_parameters
(
fsf_contract_parameters_t
*contract
,
const fsf_shared_operation_t
*shared_ops
,
size_t op_num
)
{
if (shared_ops
&& op_num
< FSF_MAX_SHARED_OPERATION
)
memcpy(&contract
->shared_operations
,shared_ops
,op_num
);
else return -1;
return 0;
}