Subversion Repositories shark

Rev

Rev 38 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 pj 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
 ------------
317 giacomo 23
 CVS :        $Id: pi.c,v 1.3 2003-11-05 15:04:14 giacomo Exp $
2 pj 24
 
25
 File:        $File$
317 giacomo 26
 Revision:    $Revision: 1.3 $
27
 Last update: $Date: 2003-11-05 15:04:14 $
2 pj 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 <modules/pi.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
 
65
/* The PI resource level descriptor */
66
typedef struct {
67
  mutex_resource_des m;   /*+ the mutex interface +*/
68
 
69
  int nlocked[MAX_PROC];  /*+ how many mutex a task currently locks +*/
70
 
71
  PID blocked[MAX_PROC];  /*+ blocked queue ... +*/
72
} PI_mutex_resource_des;
73
 
74
 
75
/* this is the structure normally pointed by the opt field in the
76
   mutex_t structure */
77
typedef struct {
78
  PID owner;
79
  int nblocked;
80
  PID firstblocked;
81
} PI_mutex_t;
82
 
83
 
84
 
38 pj 85
#if 0
2 pj 86
/*+ print resource protocol statistics...+*/
87
static void PI_resource_status(RLEVEL r)
88
{
89
  PI_mutex_resource_des *m = (PI_mutex_resource_des *)(resource_table[r]);
90
  PID i;
91
 
92
  kern_printf("Resources owned by the tasks:\n");
93
  for (i=0; i<MAX_PROC; i++) {
94
     kern_printf("%-4d", m->nlocked[i]);
95
  }
96
}
38 pj 97
#endif
2 pj 98
 
38 pj 99
static int PI_res_register(RLEVEL l, PID p, RES_MODEL *r)
2 pj 100
{
101
  /* priority inheritance works with all tasks without Resource parameters */
102
  return -1;
103
}
104
 
105
static void PI_res_detach(RLEVEL l, PID p)
106
{
107
  PI_mutex_resource_des *m = (PI_mutex_resource_des *)(resource_table[l]);
108
 
109
  if (m->nlocked[p])
110
    kern_raise(XMUTEX_OWNER_KILLED, p);
111
}
112
 
113
static int PI_init(RLEVEL l, mutex_t *m, const mutexattr_t *a)
114
{
115
  PI_mutex_t *p;
116
 
38 pj 117
  if (a->mclass != PI_MCLASS)
118
    return -1;
119
 
2 pj 120
  p = (PI_mutex_t *) kern_alloc(sizeof(PI_mutex_t));
121
 
122
  /* control if there is enough memory; no control on init on a
123
     non- destroyed mutex */
124
 
125
  if (!p)
126
    return (ENOMEM);
127
 
128
  p->owner        = NIL;
129
  p->nblocked     = 0;
130
  p->firstblocked = NIL;
131
 
132
  m->mutexlevel   = l;
133
  m->opt          = (void *)p;
134
 
135
  return 0;
136
}
137
 
138
 
139
static int PI_destroy(RLEVEL l, mutex_t *m)
140
{
141
//  PI_mutex_resource_des *lev = (PI_mutex_resource_des *)(resource_table[l]);
317 giacomo 142
  SYS_FLAGS f;
143
 
2 pj 144
  if ( ((PI_mutex_t *)m->opt)->nblocked)
145
    return (EBUSY);
146
 
317 giacomo 147
  f = kern_fsave();
2 pj 148
  if (m->opt) {
149
    kern_free(m->opt,sizeof(PI_mutex_t));
150
    m->opt = NULL;
151
  }
317 giacomo 152
  kern_frestore(f);
2 pj 153
 
154
  return 0;
155
}
156
 
157
/* Note that in this approach, when unlocking we can't wake up only
158
   one thread, but we have to wake up all the blocked threads, because there
159
   is not a concept of priority between the task... Each woken thread have
160
   to retest he condition.
161
   Normally, they retest it only one time, because if many threads are
162
   unblocked, they are scheduled basing on their priority (unkown in this
163
   module!)... and if the slice is greather than the critical sections,
164
   they never block!
165
   */
166
static int PI_lock(RLEVEL l, mutex_t *m)
167
{
168
  PI_mutex_resource_des *lev = (PI_mutex_resource_des *)(resource_table[l]);
169
  PI_mutex_t *p;
317 giacomo 170
  SYS_FLAGS f;
2 pj 171
//  return 0;
172
 
317 giacomo 173
  f =  kern_fsave();
174
 
2 pj 175
  p = (PI_mutex_t *)m->opt;
176
  if (!p) {
177
    /* if the mutex is not initialized, initialize it! */
178
    PI_mutexattr_t a;
179
    PI_mutexattr_default(a);
180
    PI_init(l, m, &a);
181
  }
182
 
183
 
184
  if (p->owner == exec_shadow) {
185
    /* the task already owns the mutex */
317 giacomo 186
    kern_frestore(f);
2 pj 187
    return (EDEADLK);
188
  }
189
 
190
  while (p->owner != NIL) {
191
    /* the mutex is locked by someone, "block" the task ...*/
192
    proc_table[exec_shadow].shadow = p->owner;
193
    lev->blocked[exec_shadow] = p->firstblocked;
194
    p->firstblocked = exec_shadow;
195
    p->nblocked++;
196
//    kern_printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
197
    /* ... call the scheduler... */
198
    scheduler();
199
    kern_context_load(proc_table[exec_shadow].context);
200
 
201
    /* ... and reaquire the cli() before the test... */
317 giacomo 202
    kern_frestore(f);
2 pj 203
  }
204
 
205
  /* the mutex is free, We can lock it! */
206
  lev->nlocked[exec_shadow]++;
207
 
208
  p->owner = exec_shadow;
209
 
317 giacomo 210
  kern_frestore(f);
2 pj 211
 
212
  return 0;
213
}
214
 
215
static int PI_trylock(RLEVEL l, mutex_t *m)
216
{
217
  PI_mutex_t *p;
317 giacomo 218
  SYS_FLAGS f;
2 pj 219
 
317 giacomo 220
  f = kern_fsave();
2 pj 221
 
222
  p = (PI_mutex_t *)m->opt;
223
  if (!p) {
224
    /* if the mutex is not initialized, initialize it! */
225
    PI_mutexattr_t a;
226
    PI_mutexattr_default(a);
227
    PI_init(l, m, &a);
228
  }
229
 
230
  if (p->owner != NIL) {
231
    /* a task already owns the mutex */
317 giacomo 232
    kern_frestore(f);
2 pj 233
    return (EBUSY);
234
  }
235
  else {
236
    /* the mutex is free */
237
    PI_mutex_resource_des *lev = (PI_mutex_resource_des *)(resource_table[l]);
238
    lev->nlocked[exec_shadow]++;
239
 
240
    p->owner = exec_shadow;
241
 
317 giacomo 242
    kern_frestore(f);
2 pj 243
    return 0;
244
  }
245
}
246
 
247
static int PI_unlock(RLEVEL l, mutex_t *m)
248
{
249
  PI_mutex_resource_des *lev;
250
  PI_mutex_t *p;
251
  int i, j;
317 giacomo 252
 
2 pj 253
//  return 0;
254
  p = (PI_mutex_t *)m->opt;
255
  if (!p)
256
    return (EINVAL);
257
 
258
  if (p->owner != exec_shadow) {
259
    /* the mutex is owned by another task!!! */
260
    return (EPERM);
261
  }
262
 
263
  proc_table[exec_shadow].context = kern_context_save();
264
 
265
  /* the mutex is mine */
266
  lev = (PI_mutex_resource_des *)(resource_table[l]);
267
  lev->nlocked[exec_shadow]--;
268
 
269
  p->owner = NIL;
270
 
271
  /* we unblock all the waiting tasks... */
272
  i = p->firstblocked;
273
  p->firstblocked = NIL;
274
 
275
  while (i != NIL) {
276
//    kern_printf("<<%d>>", i);
277
    proc_table[i].shadow = j = i;
278
    i = lev->blocked[i];
279
    lev->blocked[j] = NIL;
280
  }
281
  p->nblocked = 0;
282
 
283
/*  {
284
   int xxx;
285
   kern_printf("(PI_unlock owner=%d ",p->owner);
286
   for (xxx = 0; xxx<5; xxx++) kern_printf("p%d s%d|",xxx, proc_table[xxx].shadow);
287
   kern_printf(")\n");
288
  }*/
289
 
290
  scheduler();
291
  kern_context_load(proc_table[exec_shadow].context);
292
 
293
  return 0;
294
}
295
 
38 pj 296
RLEVEL PI_register_module(void)
2 pj 297
{
298
  RLEVEL l;                  /* the level that we register */
299
  PI_mutex_resource_des *m;  /* for readableness only */
300
  PID i;                     /* a counter */
301
 
302
  printk("PI_register_module\n");
303
 
304
  /* request an entry in the level_table */
305
  l = resource_alloc_descriptor();
306
 
307
  /* alloc the space needed for the EDF_level_des */
308
  m = (PI_mutex_resource_des *)kern_alloc(sizeof(PI_mutex_resource_des));
309
 
310
  /* update the level_table with the new entry */
311
  resource_table[l] = (resource_des *)m;
312
 
313
  /* fill the resource_des descriptor */
314
  m->m.r.rtype                       = MUTEX_RTYPE;
315
  m->m.r.res_register                = PI_res_register;
316
  m->m.r.res_detach                  = PI_res_detach;
317
 
318
  /* fill the mutex_resource_des descriptor */
319
  m->m.init                          = PI_init;
320
  m->m.destroy                       = PI_destroy;
321
  m->m.lock                          = PI_lock;
322
  m->m.trylock                       = PI_trylock;
323
  m->m.unlock                        = PI_unlock;
324
 
325
  /* fille the PI_mutex_resource_des descriptor */
326
  for (i=0; i<MAX_PROC; i++) {
327
    m->nlocked[i] = 0;
328
    m->blocked[i] = NIL;
329
  }
38 pj 330
 
331
  return l;
2 pj 332
}
333