//=====================================================================
// 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 "ll/i386/64bit.h"
#include <kernel/kern.h>
#include <modules/sem.h>
#include <modules/hartport.h>
#include <modules/cabs.h>
#include "fsf_contract.h"
#include "fsf_server.h"
#include "fsf_service_task.h"
#include "message.h"
#include <pthread.h>
#include <stdlib.h>
//#define FSF_DEBUG
int current_server
=0;
server_elem server_list
[FSF_MAX_N_SERVERS
];
bandwidth_t fsf_max_bw
= 0;
int fsf_server_level
;
PID server_task
;
PORT channel
[2];
int FSF_register_module
(int server_level
, bandwidth_t max_bw
)
{
printk
("FSF Module\n");
current_server
=0;
fsf_server_level
= server_level
;
fsf_max_bw
= max_bw
;
return 0;
}
void FSF_start_service_task
(SOFT_TASK_MODEL
*model
) {
// create the service task
// create the communication channel for negotiation and renegotiation
channel
[1] = port_create
("CHANW",sizeof(struct mess
),1,STREAM
,WRITE
);
channel
[0] = port_create
("CHANR",sizeof(struct mess
),1,STREAM
,READ
);
server_task
= task_create
("stask",service_task
,model
,NULL
);
if (server_task
== -1) {
cprintf
("error creating service task\n");
sys_shutdown_message
("Could not create service_task");
sys_end
();
return;
}
task_activate
(server_task
);
}
/* Convert the contract specification to
* budget parameters
*/
int set_SERVER_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_server_level
,5000,32);
break;
case FSF_SCHEDULER_EDF
:
local_scheduler_level
= EDFSTAR_register_level
(fsf_server_level
);
break;
case FSF_SCHEDULER_RM
:
local_scheduler_level
= RMSTAR_register_level
(fsf_server_level
);
break;
case FSF_SCHEDULER_MPEG
:
local_scheduler_level
= MPEGSTAR_register_level
(fsf_server_level
);
break;
}
if (contract
->d_equals_t
== TRUE
) {
*budget
= SERVER_setbudget
(fsf_server_level
,
TIMESPEC2USEC
(&(contract
->budget_min
)),
TIMESPEC2USEC
(&(contract
->period_max
)),
TIMESPEC2USEC
(&(contract
->period_max
)),
local_scheduler_level
,contract
->local_scheduler_id
);
} else {
*budget
= SERVER_setbudget
(fsf_server_level
,
TIMESPEC2USEC
(&(contract
->budget_min
)),
TIMESPEC2USEC
(&(contract
->period_max
)),
TIMESPEC2USEC
(&(contract
->deadline
)),
local_scheduler_level
,contract
->local_scheduler_id
);
}
return 0;
}
int adjust_SERVER_budget
(int budget
, const TIME budget_actual
,
const TIME period_actual
, const TIME dline_actual
)
{
SERVER_adjust_budget
(fsf_server_level
,
budget_actual
,
period_actual
,
dline_actual
,
budget
);
return 0;
}
/* Admission Test function */
int add_contract
(const fsf_contract_parameters_t
*contract
)
{
return 0;
}
void contract_to_server
(const fsf_contract_parameters_t
*contract
, int i
) {
TIME T
,Q
;
#ifdef FSF_DEBUG
int temp
;
#endif
T
=TIMESPEC2USEC
(&contract
->period_min
);
Q
=TIMESPEC2USEC
(&contract
->budget_max
);
mul32div32to32
(MAX_BANDWIDTH
,Q
,T
,server_list
[current_server
].
Umax);
T
=TIMESPEC2USEC
(&contract
->period_min
);
server_list
[i
].
Tmin=T
;
T
=TIMESPEC2USEC
(&contract
->period_max
);
server_list
[i
].
Tmax=T
;
Q
=TIMESPEC2USEC
(&contract
->budget_min
);
server_list
[i
].
Cmin=Q
;
mul32div32to32
(MAX_BANDWIDTH
,Q
,T
,server_list
[i
].
Umin);
server_list
[i
].
U=server_list
[i
].
Umin;
if (contract
->d_equals_t
== TRUE
) {
server_list
[i
].
deadline = 0;
server_list
[i
].
d_equals_t = TRUE
;
} else {
server_list
[i
].
deadline = TIMESPEC2USEC
(&contract
->deadline
);;
server_list
[i
].
d_equals_t = FALSE
;
}
#ifdef FSF_DEBUG
mul32div32to32
(server_list
[i
].
Umax,100, MAX_BANDWIDTH
, temp
);
kern_printf
("(Umax %d)",temp
);
mul32div32to32
(server_list
[i
].
Umin,100, MAX_BANDWIDTH
, temp
);
kern_printf
("(Umin %d)",temp
);
#endif
}
int relink_contract_to_server
(const fsf_contract_parameters_t
*contract
,
fsf_server_id_t server
)
{
int i
=0;
#ifdef FSF_DEBUG
kern_printf
("(Relink Server %d)",server
);
#endif
// find contract
while(i
<current_server
) {
if (server_list
[i
].
server==server
) break;
i
++;
}
server_list
[i
].
server=server
;
server_list
[i
].
Qs=1;
contract_to_server
(contract
, i
);
return 0;
}
int link_contract_to_server
(const fsf_contract_parameters_t
*contract
,
fsf_server_id_t server
)
{
#ifdef FSF_DEBUG
kern_printf
("(Link Server %d)",server
);
#endif
server_list
[current_server
].
server=server
;
server_list
[current_server
].
Qs=1;
contract_to_server
(contract
,current_server
);
current_server
++;
return 0;
}
int remove_contract
(fsf_server_id_t server
)
{
int i
=0;
// find the contract
while(i
<current_server
) {
if (server_list
[i
].
server==server
) break;
i
++;
}
// compress the array;
while (i
<(current_server
-1)) {
server_list
[i
].
server=server_list
[i
+1].
server;
server_list
[i
].
Umin=server_list
[i
+1].
Umin;
server_list
[i
].
U=server_list
[i
+1].
Umin;
server_list
[i
].
Umax=server_list
[i
+1].
Umax;
server_list
[i
].
Cmin=server_list
[i
+1].
Cmin;
server_list
[i
].
Tmin=server_list
[i
+1].
Tmin;
server_list
[i
].
Tmax=server_list
[i
+1].
Tmax;
server_list
[i
].
Qs=server_list
[i
+1].
Qs;
server_list
[i
].
deadline = server_list
[i
+1].
deadline;
server_list
[i
].
d_equals_t = server_list
[i
+1].
d_equals_t;
i
++;
}
current_server
--;
return 0;
}
int fsf_negotiate_contract
(const fsf_contract_parameters_t
*contract
,
fsf_server_id_t
*server
)
{
struct mess message
;
// send response server is -1 if the operation fail
message.
type=NEGOTIATE_CONTRACT
;
memmove(&message.
contract,contract
, sizeof(fsf_contract_parameters_t
));
port_send
(channel
[1],&message
,BLOCK
);
port_receive
(channel
[0], &message
, BLOCK
);
if (message.
server==-1)
return FSF_ERR_CONTRACT_REJECTED
;
*server
=message.
server;
return 0;
}
int fsf_create_thread
(fsf_server_id_t server
,
pthread_t
*thread
,
pthread_attr_t
*attr
,
fsf_thread_code_t thread_code
,
void *arg
,
void *local_scheduler_arg
)
{
int local_scheduler_level
,scheduler_id
;
#ifdef FSF_DEBUG
kern_printf
("(FSF:Insert thread = %d to Server = %d)",*thread
,server
);
#endif
/* Check if server and thread exsist */
if (server
== NIL
)
return FSF_ERR_INVALID_SERVER
;
local_scheduler_level
= SERVER_get_local_scheduler_level_from_budget
(fsf_server_level
,server
);
scheduler_id
= SERVER_get_local_scheduler_id_from_budget
(fsf_server_level
,server
);
/* Check if thread is already bind */
switch (scheduler_id
) {
case FSF_SCHEDULER_POSIX
:
nrt_task_def_arg
(*(NRT_TASK_MODEL
*)(local_scheduler_arg
),arg
);
nrt_task_def_level
(*(NRT_TASK_MODEL
*)(local_scheduler_arg
),local_scheduler_level
);
*thread
= task_create
("POSIXSTAR", thread_code
, local_scheduler_arg
, NULL
);
if (*thread
== NIL
) {
#ifdef FSF_DEBUG
kern_printf
("(FSF:Error creating thread)");
#endif
return FSF_ERR_CREATE_THREAD
;
}
POSIXSTAR_setbudget
(local_scheduler_level
, *thread
, (int)(server
));
break;
case FSF_SCHEDULER_EDF
:
hard_task_def_arg
(*(HARD_TASK_MODEL
*)(local_scheduler_arg
),arg
);
hard_task_def_level
(*(HARD_TASK_MODEL
*)(local_scheduler_arg
),local_scheduler_level
);
*thread
= task_create
("EDFSTAR", thread_code
, local_scheduler_arg
, NULL
);
if (*thread
== NIL
)
return FSF_ERR_CREATE_THREAD
;
EDFSTAR_setbudget
(local_scheduler_level
, *thread
, (int)(server
));
break;
case FSF_SCHEDULER_RM
:
hard_task_def_arg
(*(HARD_TASK_MODEL
*)(local_scheduler_arg
),arg
);
hard_task_def_level
(*(HARD_TASK_MODEL
*)(local_scheduler_arg
),local_scheduler_level
);
*thread
= task_create
("RMSTAR", thread_code
, local_scheduler_arg
, NULL
);
if (*thread
== NIL
)
return FSF_ERR_CREATE_THREAD
;
RMSTAR_setbudget
(local_scheduler_level
, *thread
, (int)(server
));
break;
case FSF_SCHEDULER_MPEG
:
hard_task_def_arg
(*(HARD_TASK_MODEL
*)(local_scheduler_arg
),arg
);
hard_task_def_level
(*(HARD_TASK_MODEL
*)(local_scheduler_arg
),local_scheduler_level
);
*thread
= task_create
("MPEGSTAR", thread_code
, local_scheduler_arg
, NULL
);
if (*thread
== NIL
)
return FSF_ERR_CREATE_THREAD
;
MPEGSTAR_setbudget
(local_scheduler_level
, *thread
, (int)(server
));
break;
default:
return FSF_ERR_INVALID_SERVER
;
break;
}
return 0;
}
int fsf_get_server
(fsf_server_id_t
*server
,
pthread_t thread
)
{
int local_scheduler_level
, scheduler_id
;
local_scheduler_level
= SERVER_get_local_scheduler_level_from_pid
(fsf_server_level
,thread
);
scheduler_id
= SERVER_get_local_scheduler_id_from_pid
(fsf_server_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
);
case FSF_SCHEDULER_MPEG
:
return MPEGSTAR_getbudget
(local_scheduler_level
,thread
);
default:
return -1;
}
return -1;
}
int fsf_get_server_level
(void)
{
return fsf_server_level
;
}
int fsf_cancel_contract
(fsf_server_id_t
*server
)
{
int local_scheduler_level
, scheduler_id
;
SYS_FLAGS f
;
TIME T
,Q
;
int i
=0;
#ifdef FSF_DEBUG
kern_printf
("(Remove server %d)",*server
);
#endif
/* Check server id */
if (*server
< 0)
return FSF_ERR_INVALID_SERVER
;
local_scheduler_level
= SERVER_get_local_scheduler_level_from_budget
(fsf_server_level
,*server
);
scheduler_id
= SERVER_get_local_scheduler_id_from_budget
(fsf_server_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;
case FSF_SCHEDULER_MPEG
:
/* Check if some thread use the server */
if(MPEGSTAR_budget_has_thread
(local_scheduler_level
,*server
))
return FSF_ERR_SERVER_USED
;
break;
}
SERVER_removebudget
(fsf_server_level
,*server
);
level_free_descriptor
(local_scheduler_level
);
remove_contract
(*server
);
f
=kern_fsave
();
if (recalculate_contract
(fsf_max_bw
)==-1) {
kern_frestore
(f
);
return FSF_ERR_CREATE_SERVER
;
}
#ifdef FSF_DEBUG
kern_printf
("(Adjust budget)");
#endif
for (i
=0; i
<current_server
; i
++) {
mul32div32to32
(MAX_BANDWIDTH
,server_list
[i
].
Cmin,server_list
[i
].
U,T
);
if (T
> server_list
[i
].
Tmin ) {
server_list
[i
].
actual_budget = server_list
[i
].
Cmin;
server_list
[i
].
actual_period = T
;
#ifdef FSF_DEBUG
kern_printf
("(1 - Q %ld T %ld)", server_list
[i
].
actual_budget, server_list
[i
].
actual_period);
#endif
if (server_list
[i
].
d_equals_t == TRUE
)
adjust_SERVER_budget
(server_list
[i
].
server,server_list
[i
].
Cmin, T
, T
);
else
adjust_SERVER_budget
(server_list
[i
].
server,server_list
[i
].
Cmin, T
, server_list
[i
].
deadline);
} else {
mul32div32to32
(server_list
[i
].
Tmin,server_list
[i
].
U,MAX_BANDWIDTH
,Q
);
server_list
[i
].
actual_budget = Q
;
server_list
[i
].
actual_period = server_list
[i
].
Tmin;
#ifdef FSF_DEBUG
kern_printf
("(2 - Q %ld T %ld)", server_list
[i
].
actual_budget, server_list
[i
].
actual_period);
#endif
if (server_list
[i
].
d_equals_t == TRUE
)
adjust_SERVER_budget
(server_list
[i
].
server,Q
, server_list
[i
].
Tmin, server_list
[i
].
Tmin);
else
adjust_SERVER_budget
(server_list
[i
].
server,Q
, server_list
[i
].
Tmin, server_list
[i
].
deadline);
}
server_list
[i
].
U=server_list
[i
].
Umin;
}
*server
= -1;
kern_frestore
(f
);
return 0;
}
int recalculate_contract
(bandwidth_t U
) {
bandwidth_t current_bandwidth
;
unsigned int temp_U
;
int Qt
;
int isok
=0;
int i
=0;
#ifdef FSF_DEBUG
int temp
;
kern_printf
("(Recalculate contract)");
#endif
/* The current bandwidth is the min bandwidth */
//current_bandwidth=SERVER_return_bandwidth(fsf_server_level);
#ifdef FSF_DEBUG
kern_printf
("(nserver %d)", current_server
);
#endif
do {
current_bandwidth
=0;
Qt
=0;
for (i
=0; i
<current_server
; i
++) {
if (server_list
[i
].
Qs!=0 && server_list
[i
].
U<server_list
[i
].
Umax)
Qt
+=server_list
[i
].
Qs;
current_bandwidth
+=server_list
[i
].
U;
}
#ifdef FSF_DEBUG
kern_printf
("(Total Quality %d)", Qt
);
#endif
isok
=1;
for (i
=0; i
<current_server
; i
++) {
if (server_list
[i
].
Qs!=0 && server_list
[i
].
U<server_list
[i
].
Umax) {
temp_U
=server_list
[i
].
U;
server_list
[i
].
U=U
-current_bandwidth
;
mul32div32to32
(server_list
[i
].
U, server_list
[i
].
Qs, Qt
, server_list
[i
].
U);
temp_U
+=server_list
[i
].
U;
if (temp_U
<=server_list
[i
].
Umin) {
server_list
[i
].
U=server_list
[i
].
Umin;
} else if (temp_U
>server_list
[i
].
Umax) {
server_list
[i
].
U=server_list
[i
].
Umax;
isok
=0;
} else server_list
[i
].
U=temp_U
;
#ifdef FSF_DEBUG
mul32div32to32
(server_list
[i
].
U,100, MAX_BANDWIDTH
, temp
);
kern_printf
("(Server %d bw %d)", server_list
[i
].
server, temp
);
#endif
}
}
} while (!isok
);
return 0;
}
int fsf_renegotiate_contract
(const fsf_contract_parameters_t
*new_contract
,
fsf_server_id_t server
)
{
struct mess message
;
// send response server is -1 if the operation fail
message.
type=RENEGOTIATE_CONTRACT
;
memmove(&message.
contract,new_contract
, sizeof(fsf_contract_parameters_t
));
message.
server = server
;
//port_send(channel,&message,BLOCK);
//port_receive(channel, &message, BLOCK);
if (message.
server==-1) return FSF_ERR_CONTRACT_REJECTED
;
return 0;
}
void print_server_list
()
{
int i
;
kern_printf
("Server List\n");
for(i
=0;i
<current_server
;i
++) {
kern_printf
("[%d] Q:%d T:%d D:%d [DeT = %d]\n",server_list
[i
].
server,(int)server_list
[i
].
actual_budget,(int)server_list
[i
].
actual_period,(int)server_list
[i
].
deadline,(int)server_list
[i
].
d_equals_t);
}
}