Subversion Repositories shark

Rev

Rev 908 | Rev 927 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
221 giacomo 1
//=====================================================================
2
//       FFFFFFIII   RRRRR      SSTTTTTTT
3
//      FF         IIR   RR    SS
4
//     FF           IR        SS
5
//    FFFFFF         RRRR    SSSSST      
6
//   FF       FI       RRR  SS
7
//  FF         II     RRR  SS
8
// FF           IIIIIR    RS 
9
//       
10
// Basic FSF(FIRST Scheduling Framework) contract management
11
// S.Ha.R.K. Implementation
12
//=====================================================================
13
 
405 trimarchi 14
#include "ll/i386/64bit.h"
679 trimarchi 15
#include <kernel/kern.h>
16
#include <modules/sem.h>
17
#include <modules/hartport.h>
18
#include <modules/cabs.h>
405 trimarchi 19
 
881 trimarchi 20
#include "fsf.h"
679 trimarchi 21
#include "fsf_service_task.h"
896 trimarchi 22
#include "fsf_server.h"
679 trimarchi 23
#include "message.h"
221 giacomo 24
 
868 trimarchi 25
#include "posixstar.h"
26
#include "edfstar.h"
27
#include "nonestar.h"
28
#include "rmstar.h"
29
 
221 giacomo 30
#include <pthread.h>
31
#include <stdlib.h>
808 trimarchi 32
#include "pistar.h"
868 trimarchi 33
#include <modules/comm_message.h>
221 giacomo 34
 
417 giacomo 35
//#define FSF_DEBUG
221 giacomo 36
 
410 trimarchi 37
int current_server=0;
407 giacomo 38
server_elem server_list[FSF_MAX_N_SERVERS];
406 giacomo 39
bandwidth_t fsf_max_bw = 0;
405 trimarchi 40
 
241 giacomo 41
int fsf_server_level;
868 trimarchi 42
int fsf_posix_level = -1;
808 trimarchi 43
int shared_object_level;
679 trimarchi 44
PID server_task;
868 trimarchi 45
fsf_contract_parameters_t contract;
221 giacomo 46
 
868 trimarchi 47
 
679 trimarchi 48
PORT channel[2];
49
 
868 trimarchi 50
fsf_server_id_t service_server = -1;
51
fsf_contract_parameters_t service_contract;
52
 
896 trimarchi 53
bandwidth_t SERVER_return_bandwidth();
54
 
808 trimarchi 55
int FSF_register_shared_object_module(void) {
811 trimarchi 56
  fsf_register_shared_object();
808 trimarchi 57
  return PISTAR_register_module();
58
}
59
 
60
 
810 trimarchi 61
int FSF_get_shared_object_level() {
62
  return shared_object_level;
63
}
64
 
868 trimarchi 65
int FSF_register_module(int posix_level, int server_level, bandwidth_t max_bw)
224 giacomo 66
{
67
  printk("FSF Module\n");
410 trimarchi 68
  current_server=0;
241 giacomo 69
  fsf_server_level = server_level;
868 trimarchi 70
  fsf_posix_level = posix_level;
406 giacomo 71
  fsf_max_bw = max_bw;
811 trimarchi 72
  shared_object_level = FSF_register_shared_object_module();
679 trimarchi 73
 
224 giacomo 74
  return 0;
75
 
76
}
77
 
868 trimarchi 78
void FSF_start_service_task(void) {
679 trimarchi 79
 
868 trimarchi 80
  int err;
881 trimarchi 81
  struct timespec default_period = FSF_SERVICE_THREAD_PERIOD;
82
  struct timespec default_budget = FSF_SERVICE_THREAD_BUDGET;
868 trimarchi 83
  DUMMY_TASK_MODEL m;
881 trimarchi 84
  fsf_sched_params_t pr;
868 trimarchi 85
 
881 trimarchi 86
  pr.policy=FSF_NONE;
87
  pr.params=&m;
88
 
868 trimarchi 89
  dummy_task_default_model(m);
90
 
679 trimarchi 91
  // create the service task
92
  // create the communication channel for negotiation and renegotiation
93
 
94
  channel[1] = port_create("CHANW",sizeof(struct mess),1,STREAM,WRITE);
95
 
96
  channel[0] = port_create("CHANR",sizeof(struct mess),1,STREAM,READ);
97
 
868 trimarchi 98
  fsf_initialize_contract(&service_contract);
99
 
100
  fsf_set_contract_basic_parameters(&service_contract,&default_budget,&default_period,FSF_DEFAULT_WORKLOAD);
101
  negotiate_contract(&service_contract,&service_server);
102
 
103
  //server_task = task_create("stask",service_task,model,NULL);
881 trimarchi 104
  err = fsf_create_local_thread(service_server,&pr, &server_task,NULL,(fsf_thread_code_t)service_task,NULL);
868 trimarchi 105
  if (err) {
679 trimarchi 106
    cprintf("error creating service task\n");
107
    sys_shutdown_message("Could not create service_task");
108
    sys_end();
109
    return;
110
  }
111
 
112
  task_activate(server_task);
113
 
114
}
115
 
116
 
221 giacomo 117
/* Convert the contract specification to
118
 * budget parameters
119
 */
241 giacomo 120
int set_SERVER_budget_from_contract
221 giacomo 121
  (const fsf_contract_parameters_t *contract,
122
   int *budget)
123
{
124
 
125
  int local_scheduler_level = 0;
126
 
868 trimarchi 127
   switch (contract->policy) {
128
     case FSF_POSIX:
241 giacomo 129
       local_scheduler_level = POSIXSTAR_register_level(fsf_server_level,5000,32);
221 giacomo 130
       break;
868 trimarchi 131
     case FSF_EDF:
241 giacomo 132
       local_scheduler_level = EDFSTAR_register_level(fsf_server_level);
221 giacomo 133
       break;
868 trimarchi 134
     case FSF_RM:
241 giacomo 135
       local_scheduler_level = RMSTAR_register_level(fsf_server_level);
221 giacomo 136
       break;
868 trimarchi 137
     case FSF_NONE:
855 trimarchi 138
       local_scheduler_level = NONESTAR_register_level(fsf_server_level);
334 giacomo 139
       break;
221 giacomo 140
   }    
405 trimarchi 141
 
908 trimarchi 142
   if (contract->d_equals_t == true) {
241 giacomo 143
  *budget = SERVER_setbudget(fsf_server_level,
221 giacomo 144
                              TIMESPEC2USEC(&(contract->budget_min)),
145
                              TIMESPEC2USEC(&(contract->period_max)),
661 giacomo 146
                              TIMESPEC2USEC(&(contract->period_max)),
868 trimarchi 147
                              local_scheduler_level,contract->policy);
661 giacomo 148
  } else {
149
  *budget = SERVER_setbudget(fsf_server_level,
150
                              TIMESPEC2USEC(&(contract->budget_min)),
151
                              TIMESPEC2USEC(&(contract->period_max)),
152
                              TIMESPEC2USEC(&(contract->deadline)),
868 trimarchi 153
                              local_scheduler_level,contract->policy);
661 giacomo 154
  }
221 giacomo 155
 
156
  return 0;
157
 
158
}
159
 
405 trimarchi 160
int adjust_SERVER_budget
161
   (int budget, const TIME budget_actual,
661 giacomo 162
    const TIME period_actual, const TIME dline_actual)
221 giacomo 163
{
164
 
241 giacomo 165
  SERVER_adjust_budget(fsf_server_level,
405 trimarchi 166
                       budget_actual,
167
                       period_actual,
661 giacomo 168
                       dline_actual,
241 giacomo 169
                       budget);
221 giacomo 170
 
171
  return 0;
172
 
173
}
174
 
175
/* Admission Test function */
176
int add_contract(const fsf_contract_parameters_t *contract)
177
{
896 trimarchi 178
  bandwidth_t current_bandwidth,U;
179
 
180
  TIME T,Q;
897 trimarchi 181
 
182
#ifdef FSF_DEBUG
183
  kern_printf("(GA TEST)");
184
#endif                                                                     
896 trimarchi 185
  T=TIMESPEC2USEC(&(contract->period_max));
186
  Q=TIMESPEC2USEC(&(contract->budget_min));
187
 
188
  mul32div32to32(MAX_BANDWIDTH,Q,T,U);
189
   /* The current bandwidth is the min bandwidth */
190
  current_bandwidth=SERVER_return_bandwidth(fsf_server_level);
191
 
897 trimarchi 192
  if (fsf_max_bw<current_bandwidth+U) return -1;
896 trimarchi 193
 
221 giacomo 194
  return 0;
195
 
196
}
197
 
687 trimarchi 198
void contract_to_server(const fsf_contract_parameters_t *contract, int i) {
199
 
410 trimarchi 200
  TIME T,Q;
201
#ifdef FSF_DEBUG
202
  int temp;
203
#endif
204
 
205
  T=TIMESPEC2USEC(&contract->period_min);
206
  Q=TIMESPEC2USEC(&contract->budget_max);
908 trimarchi 207
  server_list[i].Cmax=Q;
208
 
410 trimarchi 209
  mul32div32to32(MAX_BANDWIDTH,Q,T,server_list[current_server].Umax);
210
 
417 giacomo 211
  T=TIMESPEC2USEC(&contract->period_min);
212
  server_list[i].Tmin=T;
213
 
410 trimarchi 214
  T=TIMESPEC2USEC(&contract->period_max);
215
  server_list[i].Tmax=T;
417 giacomo 216
 
410 trimarchi 217
  Q=TIMESPEC2USEC(&contract->budget_min);
218
  server_list[i].Cmin=Q;
219
 
220
  mul32div32to32(MAX_BANDWIDTH,Q,T,server_list[i].Umin);
416 trimarchi 221
  server_list[i].U=server_list[i].Umin;
661 giacomo 222
 
908 trimarchi 223
  if (contract->d_equals_t == true) {
661 giacomo 224
    server_list[i].deadline = 0;
908 trimarchi 225
    server_list[i].d_equals_t = true;
661 giacomo 226
  } else {
227
    server_list[i].deadline = TIMESPEC2USEC(&contract->deadline);;
908 trimarchi 228
    server_list[i].d_equals_t = false;
661 giacomo 229
  }
230
 
843 trimarchi 231
  server_list[i].Qs = contract->quality;
232
  server_list[i].Is = contract->importance;
233
 
410 trimarchi 234
#ifdef FSF_DEBUG
235
  mul32div32to32(server_list[i].Umax,100, MAX_BANDWIDTH, temp);
236
  kern_printf("(Umax %d)",temp);
237
  mul32div32to32(server_list[i].Umin,100, MAX_BANDWIDTH, temp);
238
  kern_printf("(Umin %d)",temp);
239
#endif
240
 
687 trimarchi 241
}
242
 
243
int relink_contract_to_server(const fsf_contract_parameters_t *contract,
244
                              fsf_server_id_t server)
245
{
246
  int i=0;
247
#ifdef FSF_DEBUG
248
  kern_printf("(Relink Server %d)",server);
249
#endif
250
  // find contract
251
  while(i<current_server) {
252
    if (server_list[i].server==server) break;
253
    i++;
254
  }
255
 
256
  server_list[i].server=server;
843 trimarchi 257
//  server_list[i].Qs=1;
687 trimarchi 258
 
259
  contract_to_server(contract, i);
260
 
261
 
410 trimarchi 262
 return 0;
263
 
264
}
265
 
221 giacomo 266
int link_contract_to_server(const fsf_contract_parameters_t *contract,
267
                            fsf_server_id_t server)
268
{
407 giacomo 269
#ifdef FSF_DEBUG
405 trimarchi 270
  kern_printf("(Link Server %d)",server);
271
#endif
272
 
410 trimarchi 273
  server_list[current_server].server=server;
843 trimarchi 274
  //server_list[current_server].Qs=1;
405 trimarchi 275
 
687 trimarchi 276
  contract_to_server(contract,current_server);    
405 trimarchi 277
 
410 trimarchi 278
  current_server++;
221 giacomo 279
  return 0;
280
 
281
}
282
 
283
int remove_contract(fsf_server_id_t server)
284
{
405 trimarchi 285
  int i=0;
286
  // find the contract
410 trimarchi 287
  while(i<current_server) {
405 trimarchi 288
     if (server_list[i].server==server) break;
289
     i++;
290
  }
221 giacomo 291
 
405 trimarchi 292
  // compress the array;
410 trimarchi 293
  while (i<(current_server-1)) {
405 trimarchi 294
     server_list[i].server=server_list[i+1].server;
295
     server_list[i].Umin=server_list[i+1].Umin;
416 trimarchi 296
     server_list[i].U=server_list[i+1].Umin;    
405 trimarchi 297
     server_list[i].Umax=server_list[i+1].Umax;
298
     server_list[i].Cmin=server_list[i+1].Cmin;
908 trimarchi 299
     server_list[i].Cmax=server_list[i+1].Cmax;
417 giacomo 300
     server_list[i].Tmin=server_list[i+1].Tmin;
405 trimarchi 301
     server_list[i].Tmax=server_list[i+1].Tmax;
302
     server_list[i].Qs=server_list[i+1].Qs;
661 giacomo 303
     server_list[i].deadline = server_list[i+1].deadline;
304
     server_list[i].d_equals_t = server_list[i+1].d_equals_t;
843 trimarchi 305
     server_list[i].Is = server_list[i+1].Is;
417 giacomo 306
 
405 trimarchi 307
     i++;
308
  }
410 trimarchi 309
  current_server--;
405 trimarchi 310
 
311
 
221 giacomo 312
  return 0;
313
 
314
}
315
 
868 trimarchi 316
int
317
fsf_get_renegotiation_status
318
  (fsf_server_id_t server,
319
   fsf_renegotiation_status_t *renegotiation_status)
320
{
221 giacomo 321
 
868 trimarchi 322
 if (SERVER_get_renegotiation_status(fsf_server_level,server))
323
   *renegotiation_status=FSF_IN_PROGRESS;
324
 else
325
   *renegotiation_status=FSF_ADMITTED;
326
 
327
 return 0;
328
 
329
 
330
}
331
 
896 trimarchi 332
int
333
fsf_request_change_quality_and_importance
334
  (fsf_server_id_t server,
335
   int new_importance,
336
   int new_quality)
337
{
338
   struct mess m;
868 trimarchi 339
 
896 trimarchi 340
  // send response server is -1 if the operation fail
341
  m.type=CHANGE_PARAMETER;
908 trimarchi 342
  m.server=server;
343
  m.qi.quality = new_quality;
344
  m.qi.importance =  new_importance;
896 trimarchi 345
  //memmove(&m.contract,contract, sizeof(fsf_contract_parameters_t));
346
 
347
  port_send(channel[1],&m,BLOCK);
348
 
349
  port_receive(channel[0], &m, BLOCK);
350
 
351
  if (m.server==-1)
352
    return FSF_ERR_CONTRACT_REJECTED;
353
 
354
  //*server=m.server;
355
 
908 trimarchi 356
  return 0;
896 trimarchi 357
}
358
 
359
 
221 giacomo 360
int fsf_negotiate_contract
361
  (const fsf_contract_parameters_t *contract,
362
   fsf_server_id_t                 *server)
363
{
880 trimarchi 364
  struct mess m;
221 giacomo 365
 
679 trimarchi 366
  // send response server is -1 if the operation fail
880 trimarchi 367
  m.type=NEGOTIATE_CONTRACT;
368
  memmove(&m.contract,contract, sizeof(fsf_contract_parameters_t));
369
  //kern_printf("(SN:%d)",*server);
370
  port_send(channel[1],&m,BLOCK);
371
  //kern_printf("BR:%d)", *server);  
372
  port_receive(channel[0], &m, BLOCK);
373
  //kern_printf("(EN:%d)", *server);
374
  if (m.server==-1)
679 trimarchi 375
    return FSF_ERR_CONTRACT_REJECTED;
221 giacomo 376
 
880 trimarchi 377
  *server=m.server;
679 trimarchi 378
 
221 giacomo 379
  return 0;
380
 
381
}
382
 
872 trimarchi 383
int
384
fsf_negotiate_contract_for_new_thread
385
  (const fsf_contract_parameters_t *contract,
386
   fsf_server_id_t      *server,
387
   pthread_t            *thread,
388
   pthread_attr_t       *attr,
389
   fsf_thread_code_t     thread_code,
390
   void                 *arg) {
391
 
392
  int err=0;
393
 
394
  err = fsf_negotiate_contract(contract,server);
395
  if (!err) {    
396
    err = pthread_create(thread, attr, thread_code, arg);    
397
    if (!err)
398
      err = fsf_bind_thread_to_server(*server,*thread);
399
  } else return err;
400
 
401
  return err;
402
}
403
 
404
int
405
fsf_negotiate_contract_for_myself
406
  (const fsf_contract_parameters_t *contract,
407
   fsf_server_id_t      *server) {
408
 
409
  int err=0;
410
 
411
  err = fsf_negotiate_contract(contract,server);
880 trimarchi 412
  //kern_printf("ENMyS:%d", *server);
872 trimarchi 413
  if (!err) {
414
     err = fsf_bind_thread_to_server(*server,exec_shadow);
880 trimarchi 415
     //kern_printf("EMMyE:%d:%d",*server,err);
872 trimarchi 416
  } else return err;
417
 
418
  return err;
419
}
420
 
868 trimarchi 421
int fsf_unbind_thread_from_server
422
  (pthread_t       thread)
423
{
424
 
425
  int local_scheduler_level, scheduler_id;
426
 
427
  /* Move thread from the local scheduler module to posix level */
428
 
429
  #ifdef FSF_DEBUG
430
    kern_printf("(UnBind thread = %d)",thread);
431
  #endif
432
 
433
  /* Check if thread exsists */
434
  if (thread == -1)
435
    return FSF_ERR_BAD_ARGUMENT;
436
 
437
  local_scheduler_level = SERVER_get_local_scheduler_level_from_pid(fsf_server_level,thread);
438
  scheduler_id = SERVER_get_local_scheduler_id_from_pid(fsf_server_level,thread);
439
 
440
  /* Check if thread is already bind */
441
  if (scheduler_id == FSF_NONE) {
442
      /* Check if it is bind to a server */
443
      if (NONESTAR_getbudget(local_scheduler_level,thread) == -1)
444
        return FSF_ERR_BAD_ARGUMENT;
445
      else {
446
 
447
        STD_command_message *msg;
448
        NRT_TASK_MODEL nrt;
449
 
450
        nrt_task_default_model(nrt);
451
        nrt_task_def_save_arrivals(nrt);
452
 
453
        /* Send change level command to local scheduler */
454
        msg = (STD_command_message *)malloc(sizeof(STD_command_message));
455
 
456
        msg->command = STD_SET_NEW_MODEL;
457
        msg->param = (void *)(&nrt);
458
        level_table[fsf_posix_level]->public_message(fsf_posix_level,thread,msg);
459
 
460
        msg->command = STD_SET_NEW_LEVEL;
461
        msg->param = (void *)(fsf_posix_level);
462
        task_message(msg,thread,0);
463
 
464
        free(msg);
465
      }
466
  }
467
 
468
  return 0;
469
 
470
}
471
 
873 trimarchi 472
int  
473
fsf_bind_local_thread_to_server
474
  (fsf_server_id_t      server,
475
   pthread_t            thread,
476
   fsf_sched_params_t  *sched_params)
477
{
868 trimarchi 478
 
873 trimarchi 479
  STD_command_message *msg;
480
  int local_scheduler_level,scheduler_id;
481
 
482
  /* Move thread from the posix module to local scheduler */
483
 
484
  #ifdef FSF_DEBUG 
485
    kern_printf("(Bind thread = %d to Server = %d)",thread,server);
486
  #endif
487
 
488
  /* Check if server and thread exsist */
489
  if (server == -1 || thread == -1)
490
    return FSF_ERR_BAD_ARGUMENT;
491
 
492
  local_scheduler_level = SERVER_get_local_scheduler_level_from_budget(fsf_server_level,server);
493
  if (local_scheduler_level==-1)
494
    return FSF_ERR_UNKNOWN_APPSCHEDULED_THREAD;
495
 
496
  scheduler_id = SERVER_get_local_scheduler_id_from_budget(fsf_server_level,server);
881 trimarchi 497
 
498
  if (scheduler_id!=sched_params->policy)
499
     return FSF_ERR_SCHED_POLICY_NOT_COMPATIBLE;
873 trimarchi 500
 
501
  /* Check if thread is already bind */
502
  switch(scheduler_id) {
503
 
504
     case FSF_RM:
505
       {
881 trimarchi 506
         TASK_MODEL      *m=(TASK_MODEL*)(sched_params->params);
507
         HARD_TASK_MODEL *h=(HARD_TASK_MODEL *)(sched_params->params);
873 trimarchi 508
 
509
         if (m->pclass != HARD_PCLASS)
510
           return FSF_ERR_SCHED_POLICY_NOT_COMPATIBLE;
511
 
512
         h = (HARD_TASK_MODEL *)m;
513
 
514
         if (!h->wcet || !h->mit) return FSF_ERR_SCHED_POLICY_NOT_COMPATIBLE;
515
 
516
         /* now we know that m is a valid model */
517
         if (RMSTAR_getbudget(local_scheduler_level,thread) != -1)
518
           return FSF_ERR_BAD_ARGUMENT;
519
 
520
         /* Set server on local scheduler */
521
         RMSTAR_setbudget(local_scheduler_level,thread,(int)(server));
522
 
523
         /* Send change level command to posix level */
524
       }
877 trimarchi 525
       break;
526
 
873 trimarchi 527
     case FSF_EDF:
528
       {
881 trimarchi 529
         TASK_MODEL      *m=(TASK_MODEL*)(sched_params->params);
530
         HARD_TASK_MODEL *h=(HARD_TASK_MODEL *)(sched_params->params);
873 trimarchi 531
 
532
         if (m->pclass != HARD_PCLASS)
533
           return FSF_ERR_SCHED_POLICY_NOT_COMPATIBLE;
534
 
535
         h = (HARD_TASK_MODEL *)m;
536
 
537
         if (!h->wcet || !h->mit) return FSF_ERR_SCHED_POLICY_NOT_COMPATIBLE;
538
 
539
         if (EDFSTAR_getbudget(local_scheduler_level,thread) != -1)
540
           return FSF_ERR_BAD_ARGUMENT;
541
 
542
         /* Set server on local scheduler */
543
         EDFSTAR_setbudget(local_scheduler_level,thread,(int)(server));
544
 
545
       }
546
       break;
547
 
548
     case FSF_POSIX:
549
       {
881 trimarchi 550
         TASK_MODEL      *m=(TASK_MODEL*)(sched_params->params);
873 trimarchi 551
 
552
         if (m->pclass != NRT_PCLASS)
553
           return  FSF_ERR_SCHED_POLICY_NOT_COMPATIBLE;
554
 
555
         if (POSIXSTAR_getbudget(local_scheduler_level,thread) != -1)
556
           return FSF_ERR_BAD_ARGUMENT;
557
 
558
         /* Set server on local scheduler */
559
         POSIXSTAR_setbudget(local_scheduler_level,thread,(int)(server));        
560
       }
877 trimarchi 561
       break;
873 trimarchi 562
 
877 trimarchi 563
     default:
564
 
873 trimarchi 565
       return FSF_ERR_BAD_ARGUMENT;
877 trimarchi 566
 
873 trimarchi 567
  }
568
 
569
  msg = (STD_command_message *)malloc(sizeof(STD_command_message));
877 trimarchi 570
  if (msg) {
571
    SYS_FLAGS f;
572
    f=kern_fsave();
873 trimarchi 573
    msg->command = STD_SET_NEW_MODEL;
881 trimarchi 574
    msg->param = (void *)(sched_params->params);
873 trimarchi 575
    level_table[local_scheduler_level]->public_message(local_scheduler_level,thread,msg);
576
 
577
    msg->command = STD_SET_NEW_LEVEL;
578
    msg->param = (void *)(local_scheduler_level);
579
    task_message(msg,thread,0);
877 trimarchi 580
    kern_frestore(f);
873 trimarchi 581
    free(msg);
582
  } else return FSF_ERR_INTERNAL_ERROR;
583
 
584
  return 0;
585
 
586
}
587
 
588
 
868 trimarchi 589
int fsf_bind_thread_to_server
590
  (fsf_server_id_t server,
591
   pthread_t       thread)
592
{
593
 
594
  STD_command_message *msg;
595
  int local_scheduler_level,scheduler_id;
596
 
597
  /* Move thread from the posix module to local scheduler */
598
 
599
  #ifdef FSF_DEBUG 
880 trimarchi 600
    kern_printf("(Bthr=%d to Sr=%d)",thread,server);
868 trimarchi 601
  #endif
602
 
603
  /* Check if server and thread exsist */
604
  if (server == -1 || thread == -1)
605
    return FSF_ERR_BAD_ARGUMENT;
606
 
607
  local_scheduler_level = SERVER_get_local_scheduler_level_from_budget(fsf_server_level,server);
873 trimarchi 608
  if (local_scheduler_level==-1)
609
    return FSF_ERR_UNKNOWN_APPSCHEDULED_THREAD;
610
 
868 trimarchi 611
  scheduler_id = SERVER_get_local_scheduler_id_from_budget(fsf_server_level,server);
612
 
613
  /* Check if thread is already bind */
614
  if (scheduler_id == FSF_NONE) {
615
      DUMMY_TASK_MODEL rt_arg;
616
 
617
      if (NONESTAR_getbudget(local_scheduler_level,thread) != -1)
618
        return FSF_ERR_BAD_ARGUMENT;
619
 
620
      /* Set server on local scheduler */
621
      NONESTAR_setbudget(local_scheduler_level,thread,(int)(server));
622
 
623
      /* Send change level command to posix level */
624
      msg = (STD_command_message *)malloc(sizeof(STD_command_message));
625
 
626
      msg->command = STD_SET_NEW_MODEL;
627
      msg->param = (void *)(&rt_arg);
628
      level_table[local_scheduler_level]->public_message(local_scheduler_level,thread,msg);
629
 
630
      msg->command = STD_SET_NEW_LEVEL;
631
      msg->param = (void *)(local_scheduler_level);
632
      task_message(msg,thread,0);
633
      free(msg);
634
   } else return FSF_ERR_BAD_ARGUMENT;
635
 
636
  return 0;
637
}
638
 
881 trimarchi 639
int fsf_create_local_thread
640
(fsf_server_id_t        server,
641
   fsf_sched_params_t    *local_scheduler_arg,
642
   pthread_t             *thread,
643
   pthread_attr_t        *attr,
644
   fsf_thread_code_t      thread_code,
645
   void                  *arg)
221 giacomo 646
{
647
 
648
  int local_scheduler_level,scheduler_id;
649
 
650
  /* Check if server and thread exsist */
241 giacomo 651
  if (server == NIL)
873 trimarchi 652
    return  FSF_ERR_BAD_ARGUMENT;
221 giacomo 653
 
241 giacomo 654
  local_scheduler_level = SERVER_get_local_scheduler_level_from_budget(fsf_server_level,server);
655
  scheduler_id = SERVER_get_local_scheduler_id_from_budget(fsf_server_level,server);
868 trimarchi 656
#ifdef FSF_DEBUG
657
  kern_printf("sched policy %d", scheduler_id);
658
#endif
888 trimarchi 659
 
660
  if (scheduler_id!=local_scheduler_arg->policy)
661
    return FSF_ERR_SCHED_POLICY_NOT_COMPATIBLE;
662
 
221 giacomo 663
  /* Check if thread is already bind */
664
  switch (scheduler_id) {
873 trimarchi 665
     case FSF_POSIX:
221 giacomo 666
 
888 trimarchi 667
      nrt_task_def_arg(*(NRT_TASK_MODEL *)(local_scheduler_arg->params),arg);
668
      nrt_task_def_level(*(NRT_TASK_MODEL *)(local_scheduler_arg->params),local_scheduler_level);
221 giacomo 669
 
888 trimarchi 670
      *thread = task_create("POSIXSTAR", thread_code, local_scheduler_arg->params, NULL);
267 giacomo 671
      if (*thread == NIL) {
672
        #ifdef FSF_DEBUG
673
          kern_printf("(FSF:Error creating thread)");
674
        #endif
873 trimarchi 675
        return FSF_ERR_INTERNAL_ERROR;
267 giacomo 676
      }
221 giacomo 677
 
241 giacomo 678
      POSIXSTAR_setbudget(local_scheduler_level, *thread, (int)(server));
234 giacomo 679
 
221 giacomo 680
    break;
868 trimarchi 681
    case FSF_EDF:
221 giacomo 682
 
888 trimarchi 683
      hard_task_def_arg(*(HARD_TASK_MODEL *)(local_scheduler_arg->params),arg);
684
      hard_task_def_level(*(HARD_TASK_MODEL *)(local_scheduler_arg->params),local_scheduler_level);
250 giacomo 685
 
888 trimarchi 686
      *thread = task_create("EDFSTAR", thread_code, local_scheduler_arg->params, NULL);
250 giacomo 687
      if (*thread == NIL)
873 trimarchi 688
        return  FSF_ERR_INTERNAL_ERROR;
250 giacomo 689
 
690
      EDFSTAR_setbudget(local_scheduler_level, *thread, (int)(server));
691
 
221 giacomo 692
      break;
235 giacomo 693
 
868 trimarchi 694
    case FSF_RM:
235 giacomo 695
 
888 trimarchi 696
      hard_task_def_arg(*(HARD_TASK_MODEL *)(local_scheduler_arg->params),arg);
697
      hard_task_def_level(*(HARD_TASK_MODEL *)(local_scheduler_arg->params),local_scheduler_level);
273 giacomo 698
 
888 trimarchi 699
      *thread = task_create("RMSTAR", thread_code, local_scheduler_arg->params, NULL);
273 giacomo 700
      if (*thread == NIL)
873 trimarchi 701
        return  FSF_ERR_INTERNAL_ERROR;
273 giacomo 702
 
703
      RMSTAR_setbudget(local_scheduler_level, *thread, (int)(server));
704
 
705
      break;
868 trimarchi 706
    case FSF_NONE:
334 giacomo 707
 
888 trimarchi 708
      dummy_task_def_arg(*( DUMMY_TASK_MODEL *)(local_scheduler_arg->params),arg);
709
      dummy_task_def_level(*( DUMMY_TASK_MODEL *)(local_scheduler_arg->params),local_scheduler_level);
910 trimarchi 710
 
888 trimarchi 711
      *thread = task_create("NONESTAR", thread_code, local_scheduler_arg->params, NULL);
334 giacomo 712
      if (*thread == NIL)
873 trimarchi 713
        return  FSF_ERR_INTERNAL_ERROR;
334 giacomo 714
 
855 trimarchi 715
      NONESTAR_setbudget(local_scheduler_level, *thread, (int)(server));
334 giacomo 716
 
717
      break;
910 trimarchi 718
 
719
    case FSF_TABLE_DRIVEN:
720
      {
721
        DUMMY_TASK_MODEL dt;
722
        dummy_task_default_model(dt);
723
 
724
        dummy_task_def_arg(dt,arg);
725
        dummy_task_def_level(dt,local_scheduler_level);
726
 
727
        *thread = task_create("TDSTAR", thread_code, &dt, NULL);
728
        if (*thread == NIL)
729
          return  FSF_ERR_INTERNAL_ERROR;
730
 
731
        TABLEDRIVEN_setbudget(local_scheduler_level, *thread, (int)(server));
732
        TABLEDRIVEN_settable(local_scheduler_level, (fsf_table_driven_params_t *)(local_scheduler_arg->params));
733
      }
734
      break;
735
 
334 giacomo 736
 
221 giacomo 737
    default:
873 trimarchi 738
      return FSF_ERR_INTERNAL_ERROR;
221 giacomo 739
      break;
740
  }
811 trimarchi 741
 
742
  #ifdef FSF_DEBUG
743
    kern_printf("(FSF:Insert thread = %d to Server = %d)",*thread,server);
744
  #endif
221 giacomo 745
 
746
  return 0;
747
 
748
}
749
 
808 trimarchi 750
int  fsf_settask_nopreemptive
221 giacomo 751
  (fsf_server_id_t *server,
752
   pthread_t       thread)
753
{
754
  int local_scheduler_level, scheduler_id;
755
 
241 giacomo 756
  local_scheduler_level = SERVER_get_local_scheduler_level_from_pid(fsf_server_level,thread);
757
  scheduler_id = SERVER_get_local_scheduler_id_from_pid(fsf_server_level, thread);
221 giacomo 758
 
759
  switch (scheduler_id) {
868 trimarchi 760
    case FSF_POSIX:
816 trimarchi 761
      POSIXSTAR_set_nopreemtive_current(local_scheduler_level);
762
      return 1;
808 trimarchi 763
      break;
868 trimarchi 764
    case FSF_EDF:
808 trimarchi 765
      EDFSTAR_set_nopreemtive_current(local_scheduler_level);
766
      return 1;
767
      break;
868 trimarchi 768
    case FSF_RM:
812 trimarchi 769
      RMSTAR_set_nopreemtive_current(local_scheduler_level);
770
      return 1;
808 trimarchi 771
      break;
868 trimarchi 772
    case FSF_NONE:
808 trimarchi 773
      break;
774
    default:
775
      return -1;
776
  }
777
  return -1;
778
}
779
 
780
 
781
int  fsf_settask_preemptive
782
  (fsf_server_id_t *server,
783
   pthread_t       thread)
784
{
785
  int local_scheduler_level, scheduler_id;
786
 
787
  local_scheduler_level = SERVER_get_local_scheduler_level_from_pid(fsf_server_level,thread);
788
  scheduler_id = SERVER_get_local_scheduler_id_from_pid(fsf_server_level, thread);
789
 
790
  switch (scheduler_id) {
868 trimarchi 791
    case FSF_POSIX:
823 trimarchi 792
      POSIXSTAR_unset_nopreemtive_current(local_scheduler_level);
816 trimarchi 793
      return 1;
808 trimarchi 794
      break;
868 trimarchi 795
    case FSF_EDF:
808 trimarchi 796
      EDFSTAR_unset_nopreemtive_current(local_scheduler_level);
797
      return 1;
798
      break;
868 trimarchi 799
    case FSF_RM:
812 trimarchi 800
      RMSTAR_unset_nopreemtive_current(local_scheduler_level);
801
      return 1;
808 trimarchi 802
      break;
868 trimarchi 803
    case FSF_NONE:
808 trimarchi 804
      break;
805
    default:
806
      return -1;
807
  }
808
 
809
  return -1;
810
 
811
}
812
 
813
 
814
int fsf_get_server
868 trimarchi 815
  (pthread_t       thread,
816
   fsf_server_id_t *server)
808 trimarchi 817
{
818
  int local_scheduler_level, scheduler_id;
819
 
820
  local_scheduler_level = SERVER_get_local_scheduler_level_from_pid(fsf_server_level,thread);
821
  scheduler_id = SERVER_get_local_scheduler_id_from_pid(fsf_server_level, thread);
822
 
823
  switch (scheduler_id) {
868 trimarchi 824
    case FSF_POSIX:  
829 giacomo 825
      *server = POSIXSTAR_getbudget(local_scheduler_level,thread);
826
      return 0;
868 trimarchi 827
    case FSF_EDF:
829 giacomo 828
      *server = EDFSTAR_getbudget(local_scheduler_level,thread);
829
      return 0;
868 trimarchi 830
    case FSF_RM:
829 giacomo 831
      *server = RMSTAR_getbudget(local_scheduler_level,thread);
832
      return 0;
868 trimarchi 833
    case FSF_NONE:
855 trimarchi 834
      *server = NONESTAR_getbudget(local_scheduler_level,thread);
829 giacomo 835
      return 0;
235 giacomo 836
    default:
221 giacomo 837
      return -1;
838
  }
839
 
840
  return -1;
841
 
842
}
843
 
339 giacomo 844
int fsf_get_server_level(void)
845
{
846
 
847
  return fsf_server_level;
848
 
849
}
850
 
221 giacomo 851
int fsf_cancel_contract
868 trimarchi 852
  (fsf_server_id_t server)
221 giacomo 853
{
854
 
855
  int local_scheduler_level, scheduler_id;
411 trimarchi 856
  SYS_FLAGS f;
857
  TIME T,Q;
858
  int i=0;
221 giacomo 859
 
860
  #ifdef FSF_DEBUG
868 trimarchi 861
    kern_printf("(Remove server %d)",server);
221 giacomo 862
  #endif
863
 
864
  /* Check server id */
868 trimarchi 865
  if (server < 0)
873 trimarchi 866
    return FSF_ERR_BAD_ARGUMENT;
221 giacomo 867
 
868 trimarchi 868
  local_scheduler_level = SERVER_get_local_scheduler_level_from_budget(fsf_server_level,server);
869
  scheduler_id = SERVER_get_local_scheduler_id_from_budget(fsf_server_level,server);
221 giacomo 870
 
871
  switch (scheduler_id) {
868 trimarchi 872
    case FSF_POSIX:
221 giacomo 873
 
874
      /* Check if some thread use the server */
868 trimarchi 875
      if(POSIXSTAR_budget_has_thread(local_scheduler_level,server))
873 trimarchi 876
        return FSF_ERR_NOT_CONTRACTED_SERVER;
221 giacomo 877
 
878
      break;
868 trimarchi 879
    case FSF_EDF:
235 giacomo 880
      /* Check if some thread use the server */
868 trimarchi 881
      if(EDFSTAR_budget_has_thread(local_scheduler_level,server))
873 trimarchi 882
        return FSF_ERR_NOT_CONTRACTED_SERVER;
235 giacomo 883
      break;
884
 
868 trimarchi 885
    case FSF_RM:
235 giacomo 886
      /* Check if some thread use the server */
868 trimarchi 887
      if(RMSTAR_budget_has_thread(local_scheduler_level,server))
873 trimarchi 888
        return FSF_ERR_NOT_CONTRACTED_SERVER;
235 giacomo 889
 
221 giacomo 890
      break;
334 giacomo 891
 
868 trimarchi 892
    case FSF_NONE:
334 giacomo 893
      /* Check if some thread use the server */
868 trimarchi 894
      if(NONESTAR_budget_has_thread(local_scheduler_level,server))
873 trimarchi 895
        return   FSF_ERR_NOT_CONTRACTED_SERVER;
334 giacomo 896
 
897
      break;
898
 
221 giacomo 899
  }
900
 
868 trimarchi 901
  SERVER_removebudget(fsf_server_level,server);
221 giacomo 902
 
903
  level_free_descriptor(local_scheduler_level);
405 trimarchi 904
 
868 trimarchi 905
  remove_contract(server);
411 trimarchi 906
 
907
  f=kern_fsave();              
908
  if (recalculate_contract(fsf_max_bw)==-1)  {
909
       kern_frestore(f);
873 trimarchi 910
       return  FSF_ERR_INTERNAL_ERROR;
411 trimarchi 911
  }
912
#ifdef  FSF_DEBUG
913
  kern_printf("(Adjust budget)");
914
#endif    
915
  for (i=0; i<current_server; i++) {
916
    mul32div32to32(MAX_BANDWIDTH,server_list[i].Cmin,server_list[i].U,T);
417 giacomo 917
    if (T > server_list[i].Tmin ) {
411 trimarchi 918
      server_list[i].actual_budget = server_list[i].Cmin;
919
      server_list[i].actual_period = T;
417 giacomo 920
      #ifdef FSF_DEBUG
921
        kern_printf("(1 - Q %ld T %ld)", server_list[i].actual_budget, server_list[i].actual_period);
922
      #endif
661 giacomo 923
 
908 trimarchi 924
      if (server_list[i].d_equals_t == true)
661 giacomo 925
        adjust_SERVER_budget(server_list[i].server,server_list[i].Cmin, T, T);
926
      else
927
        adjust_SERVER_budget(server_list[i].server,server_list[i].Cmin, T, server_list[i].deadline);
928
 
411 trimarchi 929
    } else {
417 giacomo 930
      mul32div32to32(server_list[i].Tmin,server_list[i].U,MAX_BANDWIDTH,Q);
411 trimarchi 931
      server_list[i].actual_budget = Q;
417 giacomo 932
      server_list[i].actual_period = server_list[i].Tmin;
933
      #ifdef FSF_DEBUG
934
         kern_printf("(2 - Q %ld T %ld)", server_list[i].actual_budget, server_list[i].actual_period);
935
      #endif
661 giacomo 936
 
908 trimarchi 937
      if (server_list[i].d_equals_t == true)
661 giacomo 938
        adjust_SERVER_budget(server_list[i].server,Q, server_list[i].Tmin, server_list[i].Tmin);
939
      else
940
        adjust_SERVER_budget(server_list[i].server,Q, server_list[i].Tmin, server_list[i].deadline);
941
 
411 trimarchi 942
    }
416 trimarchi 943
    server_list[i].U=server_list[i].Umin;
411 trimarchi 944
 
945
  }                                          
221 giacomo 946
 
405 trimarchi 947
 
411 trimarchi 948
  kern_frestore(f);
221 giacomo 949
 
950
  return 0;
411 trimarchi 951
 
221 giacomo 952
}
953
 
881 trimarchi 954
bandwidth_t SERVER_return_bandwidth() {
955
  int i=0;
956
  bandwidth_t U;
957
  U=0;
958
  for(i=0;i<current_server;i++) {
959
 
960
    U+=server_list[i].Umin;
961
 
962
  }
963
 
964
  return U;
965
}
966
 
405 trimarchi 967
int recalculate_contract(bandwidth_t U) {
416 trimarchi 968
  bandwidth_t current_bandwidth;
418 giacomo 969
  unsigned int temp_U;
416 trimarchi 970
  int        Qt;
405 trimarchi 971
  int isok=0;
972
  int i=0;
868 trimarchi 973
  int target_importance=FSF_DEFAULT_IMPORTANCE;
974
 
975
#define MAX_IMPORTANCE 5
405 trimarchi 976
 
896 trimarchi 977
#ifdef FSF_DEBUG
978
  int temp;
979
 
908 trimarchi 980
  kern_printf("(RC)");
896 trimarchi 981
#endif
405 trimarchi 982
 
983
  /* The current bandwidth is the min bandwidth */
881 trimarchi 984
  current_bandwidth=SERVER_return_bandwidth(fsf_server_level);
405 trimarchi 985
  #ifdef FSF_DEBUG
908 trimarchi 986
     kern_printf("(SER%d)", current_server);
405 trimarchi 987
  #endif  
880 trimarchi 988
  //kern_printf("(CS:%d)", current_server); 
405 trimarchi 989
  do  {
990
    current_bandwidth=0;
991
    Qt=0;
410 trimarchi 992
    for (i=0; i<current_server; i++) {
843 trimarchi 993
      if (server_list[i].Is==target_importance
994
          && server_list[i].U<server_list[i].Umax && server_list[i].Qs>0)
405 trimarchi 995
         Qt+=server_list[i].Qs;
416 trimarchi 996
       current_bandwidth+=server_list[i].U;
868 trimarchi 997
#ifdef FSF_DEBUG
843 trimarchi 998
       kern_printf("(Qs %d, Qt %d, Is %d)", server_list[i].Qs, Qt,server_list[i].Is);
868 trimarchi 999
#endif
405 trimarchi 1000
    }
413 trimarchi 1001
 
868 trimarchi 1002
#ifdef FSF_DEBUG
908 trimarchi 1003
    kern_printf("(TQ%d)", Qt);
868 trimarchi 1004
#endif
405 trimarchi 1005
    isok=1;
410 trimarchi 1006
    for (i=0; i<current_server; i++) {
843 trimarchi 1007
      if (server_list[i].Is==target_importance && server_list[i].U<server_list[i].Umax && server_list[i].Qs>0) {
416 trimarchi 1008
        temp_U=server_list[i].U;
1009
        server_list[i].U=U-current_bandwidth;
1010
        mul32div32to32(server_list[i].U, server_list[i].Qs, Qt, server_list[i].U);
1011
        temp_U+=server_list[i].U;
1012
 
1013
        if (temp_U<=server_list[i].Umin) {
405 trimarchi 1014
           server_list[i].U=server_list[i].Umin;
416 trimarchi 1015
        } else if (temp_U>server_list[i].Umax)  {
1016
           server_list[i].U=server_list[i].Umax;
405 trimarchi 1017
           isok=0;
1018
        } else server_list[i].U=temp_U;
1019
 
1020
#ifdef FSF_DEBUG
1021
        mul32div32to32(server_list[i].U,100, MAX_BANDWIDTH, temp);
908 trimarchi 1022
        kern_printf("(SER %d BW %d)", server_list[i].server, temp);
405 trimarchi 1023
#endif 
1024
      }
1025
    }  
843 trimarchi 1026
    target_importance++;
880 trimarchi 1027
  } while (!isok || target_importance<=MAX_IMPORTANCE);
1028
 //kern_printf("(RNDNL)"); 
405 trimarchi 1029
 return 0;
1030
}
1031
 
221 giacomo 1032
int fsf_renegotiate_contract
1033
  (const fsf_contract_parameters_t *new_contract,
1034
   fsf_server_id_t server)
1035
{
679 trimarchi 1036
 
908 trimarchi 1037
  struct mess msg;
221 giacomo 1038
 
679 trimarchi 1039
  // send response server is -1 if the operation fail
908 trimarchi 1040
  msg.type=RENEGOTIATE_CONTRACT;
1041
  memmove(&msg.contract,new_contract, sizeof(fsf_contract_parameters_t));
1042
  msg.server = server;
1043
  //kern_printf("(REN %d)", server);
1044
  port_send(channel[1],&msg,BLOCK);
221 giacomo 1045
 
908 trimarchi 1046
  port_receive(channel[0], &msg, BLOCK);
859 trimarchi 1047
 
908 trimarchi 1048
  //kern_printf("(REN %d)", msg.server);
1049
  if (msg.server==-1) return FSF_ERR_CONTRACT_REJECTED;
679 trimarchi 1050
 
405 trimarchi 1051
   return 0;
221 giacomo 1052
}
241 giacomo 1053
 
868 trimarchi 1054
int fsf_request_contract_renegotiation
1055
  (const fsf_contract_parameters_t *new_contract,
1056
   fsf_server_id_t                  server,
1057
   int                              sig_notify,
1058
   union sigval                     sig_value)
1059
{
1060
 
908 trimarchi 1061
  struct mess msg;
868 trimarchi 1062
 
1063
  // send response server is -1 if the operation fail
908 trimarchi 1064
  msg.type=REQUEST_RENEGOTIATE_CONTRACT;
1065
  memmove(&msg.contract,new_contract, sizeof(fsf_contract_parameters_t));
1066
  msg.server = server;
910 trimarchi 1067
  msg.sig_notify=sig_notify;
1068
  msg.sig_value=sig_value;
1069
  msg.process=exec_shadow;
868 trimarchi 1070
 
908 trimarchi 1071
  port_send(channel[1],&msg,BLOCK);
868 trimarchi 1072
 
908 trimarchi 1073
  port_receive(channel[0], &msg, BLOCK);
868 trimarchi 1074
 
908 trimarchi 1075
  if (msg.server==-1) return FSF_ERR_CONTRACT_REJECTED;
868 trimarchi 1076
 
1077
   return 0;
1078
}
1079
 
407 giacomo 1080
void print_server_list()
1081
{
1082
 
1083
  int i;
1084
 
1085
  kern_printf("Server List\n");
1086
 
410 trimarchi 1087
  for(i=0;i<current_server;i++) {
407 giacomo 1088
 
662 giacomo 1089
    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);
407 giacomo 1090
 
1091
  }
1092
 
1093
}
808 trimarchi 1094
 
1095
 
1096
int fsf_get_remain_budget(fsf_server_id_t server) {
1097
 
825 trimarchi 1098
  return SERVER_get_remain_capacity(fsf_server_level, server);
808 trimarchi 1099
}
868 trimarchi 1100
 
1101
int fsf_get_budget_and_period
1102
   (fsf_server_id_t server,
1103
    struct timespec *budget,
1104
    struct timespec *period) {
1105
  TIME bg;
1106
  TIME pd;
1107
 
1108
  if (!SERVER_getbudgetinfo(fsf_server_level, &bg, &pd, NULL, server)) {
1109
    if (budget) {
1110
      NULL_TIMESPEC(budget);
1111
      ADDUSEC2TIMESPEC(bg, budget);
1112
    }
1113
    if (period) {
1114
      NULL_TIMESPEC(period);
1115
      ADDUSEC2TIMESPEC(pd, period);
1116
    }
1117
 
1118
    return 0;
1119
  }
1120
  return FSF_ERR_BAD_ARGUMENT;
1121
}
1122
 
1123
int
1124
fsf_set_service_thread_data
1125
   (const struct timespec *budget,
1126
    const struct timespec *period,
1127
    bool                  *accepted) {
1128
 
1129
  if (budget==NULL && period==NULL) return FSF_ERR_BAD_ARGUMENT;
1130
  fsf_set_contract_basic_parameters(&service_contract,budget,period,FSF_DEFAULT_WORKLOAD);
1131
  *accepted = !fsf_renegotiate_contract(&service_contract,service_server)?true:false;
1132
  return 0;
1133
 
1134
}
1135
 
1136
 
1137
 
1138
int fsf_get_service_thread_data
1139
   (struct timespec *budget,
1140
    struct timespec *period) {
1141
 
1142
  return fsf_get_budget_and_period(service_server, budget, period);
1143
 
1144
}
1145