POK(kernelpart)
lockobj.c
Go to the documentation of this file.
1 /*
2  * POK header
3  *
4  * The following file is a part of the POK project. Any modification should
5  * made according to the POK licence. You CANNOT use this file or a part of
6  * this file is this part of a file for your own project
7  *
8  * For more information on the POK licence, please see our LICENCE FILE
9  *
10  * Please follow the coding guidelines described in doc/CODING_GUIDELINES
11  *
12  * Copyright (c) 2007-2009 POK team
13  *
14  * Created by julien on Thu Jan 15 23:34:13 2009
15  */
16 
28 #if defined (POK_NEEDS_LOCKOBJECTS) || defined (POK_NEEDS_PORTS_QUEUEING) || defined (POK_NEEDS_PORTS_SAMPLING)
29 
30 #include <arch.h>
31 #include <errno.h>
32 #include <types.h>
33 #include <core/sched.h>
34 #include <core/time.h>
35 #include <core/partition.h>
36 #include <core/thread.h>
37 #include <core/lockobj.h>
38 #include <libc.h>
39 
40 pok_lockobj_t pok_partitions_lockobjs[POK_CONFIG_NB_LOCKOBJECTS+1];
41 
46 {
47 #if POK_CONFIG_NB_LOCKOBJECTS > 0
48  uint8_t i;
49 
50 #ifdef POK_NEEDS_PARTITIONS
51 #ifdef POK_NEEDS_ERROR_HANDLING
52  uint32_t total_lockobjects;
53 
54  total_lockobjects = 0;
55 
56  for ( i = 0 ; i < POK_CONFIG_NB_PARTITIONS ; i++)
57  {
58  total_lockobjects = total_lockobjects + pok_partitions[i].nlockobjs;
59  }
60 
61  if (total_lockobjects != POK_CONFIG_NB_LOCKOBJECTS)
62  {
63  pok_kernel_error (POK_ERROR_KIND_KERNEL_CONFIG);
64  }
65 #endif
66 #endif
67 
68  for ( i = 0 ; i < POK_CONFIG_NB_LOCKOBJECTS ; i++)
69  {
70  pok_partitions_lockobjs[i].spin = 0;
71  pok_partitions_lockobjs[i].is_locked = FALSE;
72  pok_partitions_lockobjs[i].initialized = FALSE;
73  }
74 #endif
75  return POK_ERRNO_OK;
76 }
77 
78 
80 {
81  uint32_t tmp;
82 
83  /* Check the policy of the lockobj */
85  {
87  }
88 
89  /* Check the kind of the locjobj, must have a declared kind
90  * If not, of course, we reject the creation.
91  */
92  if ((attr->kind != POK_LOCKOBJ_KIND_MUTEX) && (attr->kind != POK_LOCKOBJ_KIND_SEMAPHORE) && (attr->kind != POK_LOCKOBJ_KIND_EVENT))
93  {
95  }
96 
97  for (tmp = 0 ; tmp < POK_CONFIG_NB_THREADS ; tmp++ )
98  {
100  }
101 
102  obj->queueing_policy = attr->queueing_policy;
103  obj->locking_policy = attr->locking_policy;
104  obj->kind = attr->kind;
105  obj->initialized = TRUE;
106 
107  if (attr->kind == POK_LOCKOBJ_KIND_SEMAPHORE)
108  {
109  obj->current_value = attr->initial_value;
110  obj->max_value = attr->max_value;
111 
112  if (obj->current_value == 0)
113  {
114  obj->is_locked = TRUE;
115  }
116  }
117 
118  return POK_ERRNO_OK;
119 }
120 
121 #ifdef POK_NEEDS_LOCKOBJECTS
123 {
124  uint8_t i;
125  uint8_t pid;
126  uint8_t mid;
127  pok_ret_t ret;
128  uint8_t lower_bound = 0;
129  uint8_t upper_bound = 0;
130  bool_t found = FALSE;
131 
132  if ( (POK_CURRENT_PARTITION.mode != POK_PARTITION_MODE_INIT_COLD) &&
133  (POK_CURRENT_PARTITION.mode != POK_PARTITION_MODE_INIT_WARM))
134  {
135  return POK_ERRNO_MODE;
136  }
137 
138  pid = POK_SCHED_CURRENT_PARTITION;
139 
140  lower_bound = pok_partitions[pid].lockobj_index_low;
141  upper_bound = pok_partitions[pid].lockobj_index_high;
142 
143  /*
144  * Find a lockobject for the partition
145  */
146  mid = lower_bound;
147  while (mid < upper_bound)
148  {
149  if (pok_partitions_lockobjs[mid].initialized == FALSE)
150  {
151  found = TRUE; /* Yeeepeee, we found a free lockobj for this partition */
152  break;
153  }
154  mid++;
155  }
156 
157  if (found == FALSE)
158  {
160  }
161 
162  *id = mid;
163 
164  ret = pok_lockobj_create (&pok_partitions_lockobjs[mid], attr);
165 
166  if (ret != POK_ERRNO_OK)
167  {
168  return ret;
169  }
170 
171  for (i = 0 ; i < POK_CONFIG_NB_THREADS ; i++)
172  {
173  pok_partitions_lockobjs[mid].thread_state[i] = LOCKOBJ_STATE_UNLOCK;
174  }
175 
176  return POK_ERRNO_OK;
177 }
178 #endif
179 
181 {
182  pok_ret_t ret;
183 
184  SPIN_LOCK (obj->eventspin);
185 
186  if (obj->initialized == FALSE)
187  {
189  }
190 
191  if (obj->kind != POK_LOCKOBJ_KIND_EVENT)
192  {
193  return POK_ERRNO_EINVAL;
194  }
195 
196  if (pok_lockobj_unlock (obj, NULL))
197  {
198  SPIN_UNLOCK (obj->eventspin);
199  return POK_ERRNO_UNAVAILABLE;
200  }
201 
202  obj->thread_state[POK_SCHED_CURRENT_THREAD] = LOCKOBJ_STATE_WAITEVENT;
203 
204  if (timeout > 0)
205  {
206  pok_sched_lock_current_thread_timed (timeout);
207  }
208  else
209  {
210  pok_sched_lock_current_thread ();
211  }
212 
213  SPIN_UNLOCK (obj->eventspin);
214  pok_sched ();
215  obj->thread_state[POK_SCHED_CURRENT_THREAD] = LOCKOBJ_STATE_UNLOCK;
216 
217  ret = pok_lockobj_lock (obj, NULL);
218 
219  if (ret != POK_ERRNO_OK)
220  {
221  SPIN_UNLOCK (obj->eventspin);
222  return ret;
223  }
224 
225  /* Here, we come back after we wait*/
226  if ((timeout != 0 ) && (POK_GETTICK() >= timeout))
227  {
228  ret = POK_ERRNO_TIMEOUT;
229  }
230  else
231  {
232  ret = POK_ERRNO_OK;
233  }
234 
235  SPIN_UNLOCK (obj->eventspin);
236 
237  return ret;
238 }
239 
241 {
242  SPIN_LOCK (obj->eventspin);
243  uint32_t tmp;
244 
245  for (tmp = 0 ; tmp < POK_CONFIG_NB_THREADS ; tmp++)
246  {
247  if (tmp == POK_SCHED_CURRENT_THREAD)
248  continue;
249 
250  if (obj->thread_state[tmp] == LOCKOBJ_STATE_WAITEVENT)
251  {
252  pok_sched_unlock_thread (tmp);
253  SPIN_UNLOCK (obj->eventspin);
254  return POK_ERRNO_OK;
255  }
256 
257  }
258  SPIN_UNLOCK (obj->eventspin);
259  return POK_ERRNO_NOTFOUND;
260 }
261 
263 {
264  uint32_t tmp;
265  SPIN_LOCK (obj->eventspin);
266 
267  for (tmp = 0 ; tmp < POK_CONFIG_NB_THREADS ; tmp++)
268  {
269  if (tmp == POK_SCHED_CURRENT_THREAD)
270  continue;
271 
272  if (obj->thread_state[tmp] == LOCKOBJ_STATE_WAITEVENT)
273  {
274  pok_sched_unlock_thread (tmp);
275  }
276 
277  }
278 
279  SPIN_UNLOCK (obj->eventspin);
280 
281  return POK_ERRNO_OK;
282 }
283 
284 
286 {
287  uint64_t timeout = 0;
288 
289  if (obj->initialized == FALSE)
290  {
292  }
293 
294  SPIN_LOCK (obj->spin);
295 
296  if ( (obj->is_locked == FALSE ) && (obj->thread_state[POK_SCHED_CURRENT_THREAD] == LOCKOBJ_STATE_UNLOCK ))
297  {
298  obj->is_locked = TRUE;
299  SPIN_UNLOCK (obj->spin);
300  }
301  else
302  {
303  /*
304  * attr->time corresponds to the timeout for the waiting object
305  */
306  if ((attr != NULL) && (attr->time > 0))
307  {
308  timeout = attr->time;
309  }
310 
311  while ( (obj->is_locked == TRUE ) || (obj->thread_state[POK_SCHED_CURRENT_THREAD] == LOCKOBJ_STATE_LOCK))
312  {
313  obj->thread_state[POK_SCHED_CURRENT_THREAD] = LOCKOBJ_STATE_LOCK;
314 
315  if (timeout > 0)
316  {
317  pok_sched_lock_current_thread_timed (timeout);
318  if (POK_GETTICK() >= timeout)
319  {
320  obj->thread_state[POK_SCHED_CURRENT_THREAD] = LOCKOBJ_STATE_UNLOCK;
321  return POK_ERRNO_TIMEOUT;
322  }
323  }
324  else
325  {
326  pok_sched_lock_current_thread ();
327  }
328 
329  SPIN_UNLOCK (obj->spin);
330  pok_sched(); /* reschedule baby, reschedule !! */
331  }
332 
333  switch (obj->kind)
334  {
336  {
337  obj->current_value--;
338  if (obj->current_value == 0)
339  {
340  obj->is_locked = TRUE;
341  }
342  break;
343  }
344 
346  {
347  obj->is_locked = TRUE;
348  break;
349  }
350 
351  default:
352  {
353  obj->is_locked = TRUE;
354  break;
355  }
356  }
357  pok_sched_unlock_thread (POK_SCHED_CURRENT_THREAD);
358  }
359 
360  return POK_ERRNO_OK;
361 }
362 
363 
365 {
366  uint32_t res;
367 
368  (void) attr; /* unused at this time */
369 
370  if (obj->initialized == FALSE)
371  {
373  }
374 
375  res = 0;
376  SPIN_LOCK (obj->spin);
377 
378  switch (obj->kind)
379  {
381  {
382  if (obj->current_value < obj->max_value)
383  {
384  obj->current_value++;
385  }
386  obj->is_locked = FALSE;
387  break;
388  }
389 
391  {
392  obj->is_locked = FALSE;
393  break;
394  }
395 
396  default:
397  {
398  obj->is_locked = FALSE;
399  break;
400  }
401  }
402 
403  res = POK_SCHED_CURRENT_THREAD;
404  res = (res + 1) % (POK_CONFIG_NB_THREADS);
405 
406  do
407  {
408  if (obj->thread_state[res] == LOCKOBJ_STATE_LOCK)
409  {
411  pok_sched_unlock_thread (res);
412  break;
413  }
414  res = (res + 1) % (POK_CONFIG_NB_THREADS);
415  }
416  while ((res != POK_SCHED_CURRENT_THREAD));
417 
418  obj->thread_state[POK_SCHED_CURRENT_THREAD] = LOCKOBJ_STATE_UNLOCK;
419  SPIN_UNLOCK (obj->spin);
420 
421  return POK_ERRNO_OK;
422 }
423 
424 #ifdef POK_NEEDS_LOCKOBJECTS
426 {
427  /* First, we check that the locked object belongs to the partition
428  * If not, we return an error
429  */
430  pok_ret_t ret;
431 
432  if (id < pok_partitions[POK_SCHED_CURRENT_PARTITION].lockobj_index_low)
433  {
434  return POK_ERRNO_EINVAL;
435  }
436 
437  if ( id >= pok_partitions[POK_SCHED_CURRENT_PARTITION].lockobj_index_high)
438  {
439  return POK_ERRNO_EINVAL;
440  }
441 
442  if (pok_partitions_lockobjs[id].kind != attr->obj_kind)
443  {
444  return POK_ERRNO_EINVAL;
445  }
446 
447  switch (attr->operation)
448  {
450  ret = pok_lockobj_lock (&pok_partitions_lockobjs[id], attr);
451  return ret;
452  break;
453 
455  {
456  ret = pok_lockobj_unlock (&pok_partitions_lockobjs[id], attr);
457  return ret;
458  break;
459  }
460 
462  {
463  ret = pok_lockobj_eventwait (&pok_partitions_lockobjs[id], attr->time);
464  return ret;
465  break;
466  }
467 
469  {
470  ret = pok_lockobj_eventsignal (&pok_partitions_lockobjs[id]);
471  break;
472  }
473 
475  {
476  ret = pok_lockobj_eventbroadcast (&pok_partitions_lockobjs[id]);
477  break;
478  }
479 
480  default:
481  return POK_ERRNO_EINVAL;
482  }
483  return POK_ERRNO_EINVAL;
484 }
485 #endif
486 
487 #endif
488