Subversion Repositories shark

Rev

Rev 800 | Go to most recent revision | Details | 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
 ------------
23
 CVS :        $Id: pistar.c,v 1.1 2004-09-01 08:39:33 trimarchi Exp $
24
 
25
 File:        $File$
26
 Revision:    $Revision: 1.1 $
27
 Last update: $Date: 2004-09-01 08:39:33 $
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
#include <pistar.h>
55
 
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>
66
 
67
#include <tracer.h>
68
 
69
/* The PISTAR resource level descriptor */
70
typedef struct {
71
  mutex_resource_des m;   /*+ the mutex interface +*/
72
 
73
  int nlocked[MAX_PROC];  /*+ how many mutex a task currently locks +*/
74
 
75
  PID blocked[MAX_PROC];  /*+ blocked queue ... +*/
76
} PISTAR_mutex_resource_des;
77
 
78
 
79
/* this is the structure normally pointed by the opt field in the
80
   mutex_t structure */
81
typedef struct {
82
  PID owner;
83
  int nblocked;
84
  PID firstblocked;
85
  TIME wcet;
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
  p->wcet = ((PISTAR_mutexattr_t *)a)->wcet;
137
 
138
  m->mutexlevel   = l;
139
  m->opt          = (void *)p;
140
 
141
  return 0;
142
}
143
 
144
 
145
static int PISTAR_destroy(RLEVEL l, mutex_t *m)
146
{
147
//  PISTAR_mutex_resource_des *lev = (PISTAR_mutex_resource_des *)(resource_table[l]);
148
  SYS_FLAGS f;
149
 
150
  if ( ((PISTAR_mutex_t *)m->opt)->nblocked)
151
    return (EBUSY);
152
 
153
  f = kern_fsave();
154
  if (m->opt) {
155
    kern_free(m->opt,sizeof(PISTAR_mutex_t));
156
    m->opt = NULL;
157
  }
158
  kern_frestore(f);
159
 
160
  return 0;
161
}
162
 
163
/* Note that in this approach, when unlocking we can't wake up only
164
   one thread, but we have to wake up all the blocked threads, because there
165
   is not a concept of priority between the task... Each woken thread have
166
   to retest he condition.
167
   Normally, they retest it only one time, because if many threads are
168
   unblocked, they are scheduled basing on their priority (unkown in this
169
   module!)... and if the slice is greather than the critical sections,
170
   they never block!
171
   */
172
static int PISTAR_lock(RLEVEL l, mutex_t *m)
173
{
174
  PISTAR_mutex_resource_des *lev = (PISTAR_mutex_resource_des *)(resource_table[l]);
175
  PISTAR_mutex_t *p;
176
  SYS_FLAGS f;
177
//  return 0;
178
  int cond=0;
179
  fsf_server_id_t server;
180
 
181
  f =  kern_fsave();
182
 
183
  p = (PISTAR_mutex_t *)m->opt;
184
  if (!p) {
185
    /* if the mutex is not initialized, return an error! */
186
    kern_frestore(f);
187
    return (EINVAL);
188
  }
189
 
190
 
191
  if (p->owner == exec_shadow) {
192
    /* the task already owns the mutex */
193
    kern_frestore(f);
194
    return (EDEADLK);
195
  }
196
  do {
197
  while (p->owner != NIL) {
198
    /* the mutex is locked by someone, "block" the task ...*/
199
    proc_table[exec_shadow].shadow = p->owner;
200
    lev->blocked[exec_shadow] = p->firstblocked;
201
    p->firstblocked = exec_shadow;
202
    p->nblocked++;
203
//    kern_printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
204
    /* ... call the scheduler... */
205
    scheduler();
206
    TRACER_LOGEVENT(FTrace_EVT_inheritance,(unsigned short int)proc_table[exec_shadow].context,(unsigned int)proc_table[exec].context);
207
    kern_context_load(proc_table[exec_shadow].context);
208
 
209
    /* ... and reaquire the cli() before the test... */
210
    kern_cli();
211
  }
212
  fsf_get_server(&server, exec_shadow);
213
  if (fsf_get_remain_budget(server)>p->wcet) cond=1;
214
  else {
215
    SERVER_disable_server(fsf_get_server_level(),server);
216
    scheduler();
217
    kern_context_load(proc_table[exec_shadow].context);
218
    /* ... and reaquire the cli() before the test... */
219
    kern_cli();
220
  }
221
 
222
  } while(cond);
223
 
224
  /* if we are here, we have budget for critical section */
225
  /* Set the task no preemptive for the localscheduler */
226
  fsf_settask_nopreemptive(&server, exec_shadow);
227
 
228
  /* the mutex is free, We can lock it! */
229
  lev->nlocked[exec_shadow]++;
230
 
231
  p->owner = exec_shadow;
232
 
233
  kern_frestore(f);
234
 
235
  return 0;
236
}
237
 
238
static int PISTAR_trylock(RLEVEL l, mutex_t *m)
239
{
240
  PISTAR_mutex_t *p;
241
  SYS_FLAGS f;
242
 
243
  f = kern_fsave();
244
 
245
  p = (PISTAR_mutex_t *)m->opt;
246
  if (!p) {
247
    /* if the mutex is not initialized, return an error! */
248
    kern_frestore(f);
249
    return (EINVAL);
250
  }
251
 
252
  if (p->owner != NIL) {
253
    /* a task already owns the mutex */
254
    kern_frestore(f);
255
    return (EBUSY);
256
  }
257
  else {
258
    /* the mutex is free */
259
    PISTAR_mutex_resource_des *lev = (PISTAR_mutex_resource_des *)(resource_table[l]);
260
    lev->nlocked[exec_shadow]++;
261
 
262
    p->owner = exec_shadow;
263
 
264
    kern_frestore(f);
265
    return 0;
266
  }
267
}
268
 
269
static int PISTAR_unlock(RLEVEL l, mutex_t *m)
270
{
271
  PISTAR_mutex_resource_des *lev;
272
  PISTAR_mutex_t *p;
273
  int i, j;
274
  fsf_server_id_t server;
275
 
276
//  return 0;
277
  p = (PISTAR_mutex_t *)m->opt;
278
  if (!p)
279
    return (EINVAL);
280
 
281
  if (p->owner != exec_shadow) {
282
    /* the mutex is owned by another task!!! */
283
    kern_sti();
284
    return (EPERM);
285
  }
286
 
287
  proc_table[exec_shadow].context = kern_context_save();
288
 
289
  /* the mutex is mine */
290
  lev = (PISTAR_mutex_resource_des *)(resource_table[l]);
291
  lev->nlocked[exec_shadow]--;
292
 
293
  p->owner = NIL;
294
 
295
  /* we unblock all the waiting tasks... */
296
  i = p->firstblocked;
297
  p->firstblocked = NIL;
298
 
299
  while (i != NIL) {
300
//    kern_printf("<<%d>>", i);
301
    proc_table[i].shadow = j = i;
302
    i = lev->blocked[i];
303
    lev->blocked[j] = NIL;
304
  }
305
  p->nblocked = 0;
306
 
307
/*  {
308
   int xxx;
309
   kern_printf("(PISTAR_unlock owner=%d ",p->owner);
310
   for (xxx = 0; xxx<5; xxx++) kern_printf("p%d s%d|",xxx, proc_table[xxx].shadow);
311
   kern_printf(")\n");
312
  }*/
313
 
314
  /* Set the task preemptive for the localscheduler */
315
  fsf_get_server(&server, exec_shadow);
316
  fsf_settask_preemptive(&server, exec_shadow);
317
 
318
  scheduler();
319
  TRACER_LOGEVENT(FTrace_EVT_inheritance,(unsigned short int)proc_table[exec_shadow].context,(unsigned int)proc_table[exec].context);
320
  kern_context_load(proc_table[exec_shadow].context);
321
 
322
  return 0;
323
}
324
 
325
RLEVEL PISTAR_register_module(void)
326
{
327
  RLEVEL l;                  /* the level that we register */
328
  PISTAR_mutex_resource_des *m;  /* for readableness only */
329
  PID i;                     /* a counter */
330
 
331
  printk("PISTAR_register_module\n");
332
 
333
  /* request an entry in the level_table */
334
  l = resource_alloc_descriptor();
335
 
336
  /* alloc the space needed for the EDF_level_des */
337
  m = (PISTAR_mutex_resource_des *)kern_alloc(sizeof(PISTAR_mutex_resource_des));
338
 
339
  /* update the level_table with the new entry */
340
  resource_table[l] = (resource_des *)m;
341
 
342
  /* fill the resource_des descriptor */
343
  m->m.r.rtype                       = MUTEX_RTYPE;
344
  m->m.r.res_register                = PISTAR_res_register;
345
  m->m.r.res_detach                  = PISTAR_res_detach;
346
 
347
  /* fill the mutex_resource_des descriptor */
348
  m->m.init                          = PISTAR_init;
349
  m->m.destroy                       = PISTAR_destroy;
350
  m->m.lock                          = PISTAR_lock;
351
  m->m.trylock                       = PISTAR_trylock;
352
  m->m.unlock                        = PISTAR_unlock;
353
 
354
  /* fille the PISTAR_mutex_resource_des descriptor */
355
  for (i=0; i<MAX_PROC; i++) {
356
    m->nlocked[i] = 0;
357
    m->blocked[i] = NIL;
358
  }
359
 
360
  return l;
361
}
362