//=====================================================================
// 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 "cbsstar.h"
#include "posixstar.h"
#include "rmstar.h"
#include "edfstar.h"
#include "posix.h"
#include "comm_message.h"
#include <pthread.h>
#include <stdlib.h>
//#define FSF_DEBUG
int fsf_cbsstar_level
;
int fsf_posix_level
;
int FSF_register_module
(int posix_level
, int cbsstar_level
)
{
printk
("FSF Module\n");
fsf_posix_level
= posix_level
;
fsf_cbsstar_level
= cbsstar_level
;
return 0;
}
/* Convert the contract specification to
* budget parameters
*/
int set_CBSSTAR_budget_from_contract
(const fsf_contract_parameters_t
*contract
,
int *budget
)
{
int local_scheduler_level
= 0;
switch (contract
->local_scheduler_id
) {
case FSF_SCHEDULER_POSIX
:
local_scheduler_level
= POSIXSTAR_register_level
(fsf_cbsstar_level
,5000,32);
break;
case FSF_SCHEDULER_EDF
:
local_scheduler_level
= EDFSTAR_register_level
(fsf_cbsstar_level
);
break;
case FSF_SCHEDULER_RM
:
local_scheduler_level
= RMSTAR_register_level
(fsf_cbsstar_level
);
break;
}
*budget
= CBSSTAR_setbudget
(fsf_cbsstar_level
,
TIMESPEC2USEC
(&(contract
->budget_min
)),
TIMESPEC2USEC
(&(contract
->period_max
)),
local_scheduler_level
,contract
->local_scheduler_id
);
return 0;
}
int adjust_CBSSTAR_budget_from_contract
(const fsf_contract_parameters_t
*contract
,
int budget
)
{
CBSSTAR_adjust_budget
(fsf_cbsstar_level
,
TIMESPEC2USEC
(&(contract
->budget_min
)),
TIMESPEC2USEC
(&(contract
->period_max
)),
budget
);
return 0;
}
/* Admission Test function */
int add_contract
(const fsf_contract_parameters_t
*contract
)
{
return 0;
}
int link_contract_to_server
(const fsf_contract_parameters_t
*contract
,
fsf_server_id_t server
)
{
return 0;
}
int remove_contract
(fsf_server_id_t server
)
{
return 0;
}
int fsf_negotiate_contract
(const fsf_contract_parameters_t
*contract
,
fsf_server_id_t
*server
)
{
/* Check if contract is initialized */
if (!contract
) return FSF_ERR_NOT_INITIALIZED
;
/* Admission Test */
if (FSF_ADMISSION_TEST_IS_ENABLED
)
if (add_contract
(contract
))
return FSF_ERR_CONTRACT_REJECTED
;
/* SERVER = BUDGET */
set_CBSSTAR_budget_from_contract
(contract
,server
);
#ifdef FSF_DEBUG
kern_printf
("(New Server %d)",*server
);
#endif
if (*server
>= 0)
link_contract_to_server
(contract
,*server
);
else
return FSF_ERR_CREATE_SERVER
;
return 0;
}
int fsf_bind_thread_to_server
(fsf_server_id_t server
,
pthread_t thread
,
void *rt_arg
)
{
STD_command_message
*msg
;
int local_scheduler_level
,scheduler_id
;
/* Move thread from the posix module to local scheduler */
#ifdef FSF_DEBUG
kern_printf
("(Bind thread = %d to Server = %d)",thread
,server
);
#endif
/* Check if server and thread exsist */
if (server
== -1 || thread
== -1)
return FSF_ERR_BIND_THREAD
;
local_scheduler_level
= CBSSTAR_get_local_scheduler_level_from_budget
(fsf_cbsstar_level
,server
);
scheduler_id
= CBSSTAR_get_local_scheduler_id_from_budget
(fsf_cbsstar_level
,server
);
/* Check if thread is already bind */
switch (scheduler_id
) {
case FSF_SCHEDULER_POSIX
:
if (POSIXSTAR_getbudget
(local_scheduler_level
,thread
) != -1)
return FSF_ERR_BIND_THREAD
;
/* Set server on local scheduler */
POSIXSTAR_setbudget
(local_scheduler_level
,thread
,(int)(server
));
/* Send change level command to posix level */
msg
= (STD_command_message
*)malloc(sizeof(STD_command_message
));
#ifdef FSF_DEBUG
kern_printf
("(MSG POSIXSTAR LEV %d SER %d THR %d)",local_scheduler_level
,server
,thread
);
#endif
msg
->command
= STD_SET_NEW_MODEL
;
msg
->param
= (void *)(rt_arg
);
level_table
[local_scheduler_level
]->public_message
(local_scheduler_level
,thread
,msg
);
msg
->command
= STD_SET_NEW_LEVEL
;
msg
->param
= (void *)(local_scheduler_level
);
task_message
(msg
,thread
,0);
free(msg
);
break;
case FSF_SCHEDULER_EDF
:
if (EDFSTAR_getbudget
(local_scheduler_level
,thread
) != -1)
return FSF_ERR_BIND_THREAD
;
/* Set server on local scheduler */
EDFSTAR_setbudget
(local_scheduler_level
,thread
,(int)(server
));
/* Send change level command to posix level */
msg
= (STD_command_message
*)malloc(sizeof(STD_command_message
));
#ifdef FSF_DEBUG
kern_printf
("(MSG EDFSTAR LEV %d SEV %d THR %d)",local_scheduler_level
,server
,thread
);
#endif
msg
->command
= STD_SET_NEW_MODEL
;
msg
->param
= (void *)(rt_arg
);
level_table
[local_scheduler_level
]->public_message
(local_scheduler_level
,thread
,msg
);
msg
->command
= STD_SET_NEW_LEVEL
;
msg
->param
= (void *)(local_scheduler_level
);
task_message
(msg
,thread
,0);
free(msg
);
break;
case FSF_SCHEDULER_RM
:
if (RMSTAR_getbudget
(local_scheduler_level
,thread
) != -1)
return FSF_ERR_BIND_THREAD
;
/* Set server on local scheduler */
RMSTAR_setbudget
(local_scheduler_level
,thread
,(int)(server
));
/* Send change level command to posix level */
msg
= (STD_command_message
*)malloc(sizeof(STD_command_message
));
#ifdef FSF_DEBUG
kern_printf
("(MSG RMSTAR LEV %d SEV %d THR %d)",local_scheduler_level
,server
,thread
);
#endif
msg
->command
= STD_SET_NEW_MODEL
;
msg
->param
= (void *)(rt_arg
);
level_table
[local_scheduler_level
]->public_message
(local_scheduler_level
,thread
,msg
);
msg
->command
= STD_SET_NEW_LEVEL
;
msg
->param
= (void *)(local_scheduler_level
);
task_message
(msg
,thread
,0);
default:
return FSF_ERR_BIND_THREAD
;
break;
}
return 0;
}
int fsf_unbind_thread_from_server
(pthread_t thread
)
{
int local_scheduler_level
, scheduler_id
;
/* Move thread from the local scheduler module to posix level */
#ifdef FSF_DEBUG
kern_printf
("(UnBind thread = %d)",thread
);
#endif
/* Check if thread exsists */
if (thread
== -1)
return FSF_ERR_UNBIND_THREAD
;
local_scheduler_level
= CBSSTAR_get_local_scheduler_level_from_pid
(fsf_cbsstar_level
,thread
);
scheduler_id
= CBSSTAR_get_local_scheduler_id_from_pid
(fsf_cbsstar_level
,thread
);
switch (scheduler_id
) {
case FSF_SCHEDULER_POSIX
:
/* Check if it is bind to a server */
if (POSIXSTAR_getbudget
(local_scheduler_level
,thread
) == -1)
return FSF_ERR_UNBIND_THREAD
;
else {
STD_command_message
*msg
;
NRT_TASK_MODEL nrt
;
nrt_task_default_model
(nrt
);
nrt_task_def_save_arrivals
(nrt
);
/* Send change level command to local scheduler */
msg
= (STD_command_message
*)malloc(sizeof(STD_command_message
));
msg
->command
= STD_SET_NEW_MODEL
;
msg
->param
= (void *)(&nrt
);
level_table
[fsf_posix_level
]->public_message
(fsf_posix_level
,thread
,msg
);
msg
->command
= STD_SET_NEW_LEVEL
;
msg
->param
= (void *)(fsf_posix_level
);
task_message
(msg
,thread
,0);
free(msg
);
}
break;
case FSF_SCHEDULER_EDF
:
if (EDFSTAR_getbudget
(local_scheduler_level
,thread
) == -1)
return FSF_ERR_UNBIND_THREAD
;
else {
STD_command_message
*msg
;
NRT_TASK_MODEL nrt
;
nrt_task_default_model
(nrt
);
nrt_task_def_save_arrivals
(nrt
);
/* Send change level command to local scheduler */
msg
= (STD_command_message
*)malloc(sizeof(STD_command_message
));
msg
->command
= STD_SET_NEW_MODEL
;
msg
->param
= (void *)(&nrt
);
level_table
[fsf_posix_level
]->public_message
(fsf_posix_level
,thread
,msg
);
msg
->command
= STD_SET_NEW_LEVEL
;
msg
->param
= (void *)(fsf_posix_level
);
task_message
(msg
,thread
,0);
free(msg
);
}
break;
case FSF_SCHEDULER_RM
:
if (RMSTAR_getbudget
(local_scheduler_level
,thread
) == -1)
return FSF_ERR_UNBIND_THREAD
;
else {
STD_command_message
*msg
;
NRT_TASK_MODEL nrt
;
nrt_task_default_model
(nrt
);
nrt_task_def_save_arrivals
(nrt
);
/* Send change level command to local scheduler */
msg
= (STD_command_message
*)malloc(sizeof(STD_command_message
));
msg
->command
= STD_SET_NEW_MODEL
;
msg
->param
= (void *)(&nrt
);
level_table
[fsf_posix_level
]->public_message
(fsf_posix_level
,thread
,msg
);
msg
->command
= STD_SET_NEW_LEVEL
;
msg
->param
= (void *)(fsf_posix_level
);
task_message
(msg
,thread
,0);
free(msg
);
}
break;
}
return 0;
}
int fsf_negotiate_contract_for_new_thread
(const fsf_contract_parameters_t
*contract
,
fsf_server_id_t
*server
,
pthread_t
*thread
,
pthread_attr_t
*attr
,
fsf_thread_code_t thread_code
,
void *arg
,
void *rt_arg
)
{
int error
;
/* Create server */
error
= fsf_negotiate_contract
(contract
, server
);
if (error
) return error
;
/* Create pthread */
if (pthread_create
(thread
, attr
, thread_code
, arg
))
return FSF_ERR_CREATE_THREAD
;
/* Bind thread to server */
error
= fsf_bind_thread_to_server
(*server
, *thread
, rt_arg
);
if (error
) return error
;
return 0;
}
int fsf_negotiate_contract_for_myself
(const fsf_contract_parameters_t
*contract
,
fsf_server_id_t
*server
,
void *rt_arg
)
{
int error
;
/* Create server */
error
= fsf_negotiate_contract
(contract
, server
);
if (error
) return error
;
/* Bind current thread to server */
error
= fsf_bind_thread_to_server
(*server
, exec_shadow
, rt_arg
);
if (error
) return error
;
return 0;
}
int fsf_get_server
(fsf_server_id_t
*server
,
pthread_t thread
)
{
int local_scheduler_level
, scheduler_id
;
local_scheduler_level
= CBSSTAR_get_local_scheduler_level_from_pid
(fsf_cbsstar_level
,thread
);
scheduler_id
= CBSSTAR_get_local_scheduler_id_from_pid
(fsf_cbsstar_level
, thread
);
switch (scheduler_id
) {
case FSF_SCHEDULER_POSIX
:
return POSIXSTAR_getbudget
(local_scheduler_level
,thread
);
case FSF_SCHEDULER_EDF
:
return EDFSTAR_getbudget
(local_scheduler_level
,thread
);
case FSF_SCHEDULER_RM
:
return RMSTAR_getbudget
(local_scheduler_level
,thread
);
default:
return -1;
}
return -1;
}
int fsf_cancel_contract
(fsf_server_id_t
*server
)
{
int local_scheduler_level
, scheduler_id
;
#ifdef FSF_DEBUG
kern_printf
("(Remove server %d)",*server
);
#endif
/* Check server id */
if (*server
< 0)
return FSF_ERR_INVALID_SERVER
;
local_scheduler_level
= CBSSTAR_get_local_scheduler_level_from_budget
(fsf_cbsstar_level
,*server
);
scheduler_id
= CBSSTAR_get_local_scheduler_id_from_budget
(fsf_cbsstar_level
,*server
);
switch (scheduler_id
) {
case FSF_SCHEDULER_POSIX
:
/* Check if some thread use the server */
if(POSIXSTAR_budget_has_thread
(local_scheduler_level
,*server
))
return FSF_ERR_SERVER_USED
;
break;
case FSF_SCHEDULER_EDF
:
/* Check if some thread use the server */
if(EDFSTAR_budget_has_thread
(local_scheduler_level
,*server
))
return FSF_ERR_SERVER_USED
;
break;
case FSF_SCHEDULER_RM
:
/* Check if some thread use the server */
if(RMSTAR_budget_has_thread
(local_scheduler_level
,*server
))
return FSF_ERR_SERVER_USED
;
break;
}
CBSSTAR_removebudget
(fsf_cbsstar_level
,*server
);
level_free_descriptor
(local_scheduler_level
);
remove_contract
(*server
);
*server
= -1;
return 0;
}
int fsf_renegotiate_contract
(const fsf_contract_parameters_t
*new_contract
,
fsf_server_id_t server
)
{
#ifdef FSF_DEBUG
kern_printf
("(Renegotiate for server %d)",server
);
#endif
if (!new_contract
)
return FSF_ERR_NOT_INITIALIZED
;
if (server
< 0)
return FSF_ERR_INVALID_SERVER
;
return adjust_CBSSTAR_budget_from_contract
(new_contract
,server
);
}