Subversion Repositories shark

Rev

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

Rev Author Line No. Line
793 trimarchi 1
/*
2
 * Project: S.Ha.R.K.
3
 *
4
 * Coordinators:
5
 *   Giorgio Buttazzo    <giorgio@sssup.it>
6
 *   Paolo Gai           <pj@gandalf.sssup.it>
7
 *
8
 * Authors     :
9
 *   Paolo Gai           <pj@gandalf.sssup.it>
10
 *   Massimiliano Giorgi <massy@gandalf.sssup.it>
11
 *   Luca Abeni          <luca@gandalf.sssup.it>
12
 *   (see the web pages for full authors list)
13
 *
14
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
15
 *
16
 * http://www.sssup.it
17
 * http://retis.sssup.it
18
 * http://shark.sssup.it
19
 */
20
 
21
/**
22
 ------------
829 giacomo 23
 CVS :        $Id: pistar.c,v 1.8 2004-09-08 16:51:34 giacomo Exp $
793 trimarchi 24
 
25
 File:        $File$
829 giacomo 26
 Revision:    $Revision: 1.8 $
27
 Last update: $Date: 2004-09-08 16:51:34 $
793 trimarchi 28
 ------------
29
 
30
 Priority Inhertitance protocol. see pi.h for more details...
31
 
32
**/
33
 
34
/*
35
 * Copyright (C) 2000 Paolo Gai
36
 *
37
 * This program is free software; you can redistribute it and/or modify
38
 * it under the terms of the GNU General Public License as published by
39
 * the Free Software Foundation; either version 2 of the License, or
40
 * (at your option) any later version.
41
 *
42
 * This program is distributed in the hope that it will be useful,
43
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
44
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
45
 * GNU General Public License for more details.
46
 *
47
 * You should have received a copy of the GNU General Public License
48
 * along with this program; if not, write to the Free Software
49
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
50
 *
51
 */
52
 
53
 
54
 
800 trimarchi 55
 
793 trimarchi 56
#include <ll/ll.h>
57
#include <ll/string.h>
58
#include <ll/stdio.h>
59
#include <kernel/const.h>
60
#include <sys/types.h>
61
#include <kernel/descr.h>
62
#include <kernel/var.h>
63
#include <kernel/func.h>
64
#include <fsf_contract.h>
65
#include <fsf_server.h>
800 trimarchi 66
#include <pistar.h>
793 trimarchi 67
 
68
#include <tracer.h>
69
 
70
/* The PISTAR resource level descriptor */
71
typedef struct {
72
  mutex_resource_des m;   /*+ the mutex interface +*/
73
 
74
  int nlocked[MAX_PROC];  /*+ how many mutex a task currently locks +*/
75
 
76
  PID blocked[MAX_PROC];  /*+ blocked queue ... +*/
77
} PISTAR_mutex_resource_des;
78
 
79
 
80
/* this is the structure normally pointed by the opt field in the
81
   mutex_t structure */
82
typedef struct {
83
  PID owner;
84
  int nblocked;
85
  PID firstblocked;
86
} PISTAR_mutex_t;
87
 
88
 
89
 
90
#if 0
91
/*+ print resource protocol statistics...+*/
92
static void PISTAR_resource_status(RLEVEL r)
93
{
94
  PISTAR_mutex_resource_des *m = (PISTAR_mutex_resource_des *)(resource_table[r]);
95
  PID i;
96
 
97
  kern_printf("Resources owned by the tasks:\n");
98
  for (i=0; i<MAX_PROC; i++) {
99
     kern_printf("%-4d", m->nlocked[i]);
100
  }
101
}
102
#endif
103
 
104
static int PISTAR_res_register(RLEVEL l, PID p, RES_MODEL *r)
105
{
106
  /* priority inheritance works with all tasks without Resource parameters */
107
  return -1;
108
}
109
 
110
static void PISTAR_res_detach(RLEVEL l, PID p)
111
{
112
  PISTAR_mutex_resource_des *m = (PISTAR_mutex_resource_des *)(resource_table[l]);
113
 
114
  if (m->nlocked[p])
115
    kern_raise(XMUTEX_OWNER_KILLED, p);
116
}
117
 
118
static int PISTAR_init(RLEVEL l, mutex_t *m, const mutexattr_t *a)
119
{
120
  PISTAR_mutex_t *p;
121
 
122
  if (a->mclass != PISTAR_MCLASS)
123
    return -1;
124
 
125
  p = (PISTAR_mutex_t *) kern_alloc(sizeof(PISTAR_mutex_t));
126
 
127
  /* control if there is enough memory; no control on init on a
128
     non- destroyed mutex */
129
 
130
  if (!p)
131
    return (ENOMEM);
132
 
133
  p->owner        = NIL;
134
  p->nblocked     = 0;
135
  p->firstblocked = NIL;
136
 
137
  m->mutexlevel   = l;
138
  m->opt          = (void *)p;
139
 
140
  return 0;
141
}
142
 
143
 
144
static int PISTAR_destroy(RLEVEL l, mutex_t *m)
145
{
146
//  PISTAR_mutex_resource_des *lev = (PISTAR_mutex_resource_des *)(resource_table[l]);
147
  SYS_FLAGS f;
148
 
149
  if ( ((PISTAR_mutex_t *)m->opt)->nblocked)
150
    return (EBUSY);
151
 
152
  f = kern_fsave();
153
  if (m->opt) {
154
    kern_free(m->opt,sizeof(PISTAR_mutex_t));
155
    m->opt = NULL;
156
  }
157
  kern_frestore(f);
158
 
159
  return 0;
160
}
161
 
162
/* Note that in this approach, when unlocking we can't wake up only
163
   one thread, but we have to wake up all the blocked threads, because there
164
   is not a concept of priority between the task... Each woken thread have
165
   to retest he condition.
166
   Normally, they retest it only one time, because if many threads are
167
   unblocked, they are scheduled basing on their priority (unkown in this
168
   module!)... and if the slice is greather than the critical sections,
169
   they never block!
170
   */
806 trimarchi 171
int PISTAR_lock(RLEVEL l, mutex_t *m, TIME wcet)
793 trimarchi 172
{
173
  PISTAR_mutex_resource_des *lev = (PISTAR_mutex_resource_des *)(resource_table[l]);
174
  PISTAR_mutex_t *p;
175
  SYS_FLAGS f;
176
//  return 0;
809 trimarchi 177
  int cond;
178
  cond = 1;
793 trimarchi 179
  fsf_server_id_t server;
180
 
181
  f =  kern_fsave();
829 giacomo 182
 
183
  TRACER_LOGEVENT(FTrace_EVT_set_mutex_lock,(unsigned short int)proc_table[exec_shadow].context,(unsigned int)m);
184
 
811 trimarchi 185
  //kern_printf("(PISTAR lock)");
793 trimarchi 186
  p = (PISTAR_mutex_t *)m->opt;
187
  if (!p) {
188
    /* if the mutex is not initialized, return an error! */
189
    kern_frestore(f);
190
    return (EINVAL);
191
  }
192
 
193
 
194
  if (p->owner == exec_shadow) {
195
    /* the task already owns the mutex */
196
    kern_frestore(f);
197
    return (EDEADLK);
198
  }
199
  do {
200
  while (p->owner != NIL) {
201
    /* the mutex is locked by someone, "block" the task ...*/
202
    proc_table[exec_shadow].shadow = p->owner;
203
    lev->blocked[exec_shadow] = p->firstblocked;
204
    p->firstblocked = exec_shadow;
205
    p->nblocked++;
206
//    kern_printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
207
    /* ... call the scheduler... */
208
    scheduler();
209
    TRACER_LOGEVENT(FTrace_EVT_inheritance,(unsigned short int)proc_table[exec_shadow].context,(unsigned int)proc_table[exec].context);
210
    kern_context_load(proc_table[exec_shadow].context);
211
 
212
    /* ... and reaquire the cli() before the test... */
213
    kern_cli();
214
  }
215
  fsf_get_server(&server, exec_shadow);
809 trimarchi 216
  if (fsf_get_remain_budget(server)>wcet) cond=0;
793 trimarchi 217
  else {
218
    SERVER_disable_server(fsf_get_server_level(),server);
219
    scheduler();
823 trimarchi 220
 
793 trimarchi 221
    kern_context_load(proc_table[exec_shadow].context);
222
    /* ... and reaquire the cli() before the test... */
223
    kern_cli();
224
  }
225
 
226
  } while(cond);
227
 
228
  /* if we are here, we have budget for critical section */
229
  /* Set the task no preemptive for the localscheduler */
811 trimarchi 230
  //kern_printf("(PISTAR NP %d", exec_shadow);
793 trimarchi 231
  fsf_settask_nopreemptive(&server, exec_shadow);
232
 
233
  /* the mutex is free, We can lock it! */
234
  lev->nlocked[exec_shadow]++;
235
 
236
  p->owner = exec_shadow;
237
 
238
  kern_frestore(f);
239
 
240
  return 0;
241
}
242
 
243
static int PISTAR_trylock(RLEVEL l, mutex_t *m)
244
{
245
  PISTAR_mutex_t *p;
246
  SYS_FLAGS f;
247
 
248
  f = kern_fsave();
249
 
250
  p = (PISTAR_mutex_t *)m->opt;
251
  if (!p) {
252
    /* if the mutex is not initialized, return an error! */
253
    kern_frestore(f);
254
    return (EINVAL);
255
  }
256
 
257
  if (p->owner != NIL) {
258
    /* a task already owns the mutex */
259
    kern_frestore(f);
260
    return (EBUSY);
261
  }
262
  else {
263
    /* the mutex is free */
264
    PISTAR_mutex_resource_des *lev = (PISTAR_mutex_resource_des *)(resource_table[l]);
265
    lev->nlocked[exec_shadow]++;
266
 
267
    p->owner = exec_shadow;
268
 
269
    kern_frestore(f);
270
    return 0;
271
  }
272
}
273
 
274
static int PISTAR_unlock(RLEVEL l, mutex_t *m)
275
{
276
  PISTAR_mutex_resource_des *lev;
277
  PISTAR_mutex_t *p;
278
  int i, j;
279
  fsf_server_id_t server;
823 trimarchi 280
  //kern_printf("PISTAR unlock");
793 trimarchi 281
//  return 0;
282
  p = (PISTAR_mutex_t *)m->opt;
283
  if (!p)
284
    return (EINVAL);
285
 
286
  if (p->owner != exec_shadow) {
287
    /* the mutex is owned by another task!!! */
288
    kern_sti();
289
    return (EPERM);
290
  }
291
 
292
  proc_table[exec_shadow].context = kern_context_save();
293
 
294
  /* the mutex is mine */
295
  lev = (PISTAR_mutex_resource_des *)(resource_table[l]);
296
  lev->nlocked[exec_shadow]--;
297
 
298
  p->owner = NIL;
299
 
300
  /* we unblock all the waiting tasks... */
301
  i = p->firstblocked;
302
  p->firstblocked = NIL;
303
 
304
  while (i != NIL) {
305
//    kern_printf("<<%d>>", i);
306
    proc_table[i].shadow = j = i;
307
    i = lev->blocked[i];
308
    lev->blocked[j] = NIL;
309
  }
310
  p->nblocked = 0;
311
 
312
/*  {
313
   int xxx;
811 trimarchi 314
   //kern_printf("(PISTAR_unlock owner=%d ",p->owner);
793 trimarchi 315
   for (xxx = 0; xxx<5; xxx++) kern_printf("p%d s%d|",xxx, proc_table[xxx].shadow);
316
   kern_printf(")\n");
317
  }*/
318
 
319
  /* Set the task preemptive for the localscheduler */
320
  fsf_get_server(&server, exec_shadow);
321
  fsf_settask_preemptive(&server, exec_shadow);
322
 
323
  scheduler();
324
  TRACER_LOGEVENT(FTrace_EVT_inheritance,(unsigned short int)proc_table[exec_shadow].context,(unsigned int)proc_table[exec].context);
325
  kern_context_load(proc_table[exec_shadow].context);
326
 
327
  return 0;
328
}
329
 
330
RLEVEL PISTAR_register_module(void)
331
{
332
  RLEVEL l;                  /* the level that we register */
333
  PISTAR_mutex_resource_des *m;  /* for readableness only */
334
  PID i;                     /* a counter */
335
 
336
  printk("PISTAR_register_module\n");
337
 
338
  /* request an entry in the level_table */
339
  l = resource_alloc_descriptor();
340
 
341
  /* alloc the space needed for the EDF_level_des */
342
  m = (PISTAR_mutex_resource_des *)kern_alloc(sizeof(PISTAR_mutex_resource_des));
343
 
344
  /* update the level_table with the new entry */
345
  resource_table[l] = (resource_des *)m;
346
 
347
  /* fill the resource_des descriptor */
348
  m->m.r.rtype                       = MUTEX_RTYPE;
349
  m->m.r.res_register                = PISTAR_res_register;
350
  m->m.r.res_detach                  = PISTAR_res_detach;
351
 
352
  /* fill the mutex_resource_des descriptor */
353
  m->m.init                          = PISTAR_init;
354
  m->m.destroy                       = PISTAR_destroy;
806 trimarchi 355
  m->m.lock                          = NULL;
793 trimarchi 356
  m->m.trylock                       = PISTAR_trylock;
357
  m->m.unlock                        = PISTAR_unlock;
358
 
359
  /* fille the PISTAR_mutex_resource_des descriptor */
360
  for (i=0; i<MAX_PROC; i++) {
361
    m->nlocked[i] = 0;
362
    m->blocked[i] = NIL;
363
  }
364
 
365
  return l;
366
}
367