source: soft/giet_vm/libs/barrier.c @ 166

Last change on this file since 166 was 165, checked in by alain, 12 years ago

Introducing various modifications in kernel initialisation

File size: 3.5 KB
Line 
1//////////////////////////////////////////////////////////////////////////////////
2// File     : barrier.c     
3// Date     : 01/04/2012
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// These barrier.c and barrier.h files are part of the GIET nano-kernel.
8// This user-level library provides a synchronisation service between several
9// tasks sharing the same address space in a parallel multi-tasks application.
10// Neither the barrier_init(), nor the barrier_wait() function require a syscall.
11// The barrier itself must have been allocated in a shared data segment.
12///////////////////////////////////////////////////////////////////////////////////
13
14#include "barrier.h"
15
16///////////////////////////////////////////////////////////////////////////////////
17//      barrier_init()
18// This function makes a cooperative initialisation of the barrier:
19// several tasks try to initialize the barrier, but the initialisation
20// is done by only one task, using LL/SC instructions.
21///////////////////////////////////////////////////////////////////////////////////
22void barrier_init( giet_barrier_t*      barrier, 
23                   unsigned int         value )
24{
25    unsigned int* pinit  = (unsigned int*)&barrier->init;
26    unsigned int* pcount = (unsigned int*)&barrier->count;
27
28    // parallel initialisation using atomic instructions LL/SC
29    // inputs : pinit, pcount, value
30    // no output
31    asm volatile ("_barrier_init_test:                  \n"
32                  "ll   $2,     0(%0)                   \n" /* read initial value */
33                  "bnez $2,     _barrier_init_done      \n"
34                  "move $3,     %2                      \n"
35                  "sc   $3,     0(%0)                   \n" /* write initial value */
36                  "beqz $3,     _barrier_init_test      \n"
37                  "move $3,     %2                      \n"
38                  "sw   $3,     0(%1)                   \n" /* write count */
39                  "_barrier_init_done:                  \n"
40                  :: "r"(pinit), "r"(pcount), "r"(value)
41                  : "$2", "$3");
42}
43///////////////////////////////////////////////////////////////////////////////////
44//      barrier_wait()
45// This blocking function uses LL/SC to decrement the barrier's counter.
46// Then, it uses a busy_waiting mechanism if it is not the last.
47// (because the GIET does not support dynamic task scheduling/descheduling)
48///////////////////////////////////////////////////////////////////////////////////
49void barrier_wait( giet_barrier_t* barrier )
50{
51    unsigned int* pcount  = (unsigned int*)&barrier->count;
52    unsigned int maxcount = barrier->init;
53    unsigned int count;
54
55    // parallel decrement barrier counter using atomic instructions LL/SC
56    // - input : pointer on the barrier counter
57    // - output : counter value
58    asm volatile ("_barrier_decrement:          \n"
59                  "ll   %0, 0(%1)               \n"
60                  "addi $3, %0,     -1          \n"
61                  "sc   $3, 0(%1)               \n"
62                  "beqz $3, _barrier_decrement  \n"
63                  : "=&r"(count)
64                  : "r"(pcount)
65                  : "$2", "$3");
66
67    // the last task re-initializes the barrier counter to the max value,
68    // waking up all other waiting tasks
69
70    if (count == 1)             // last task
71    {
72        *pcount = maxcount;
73    }
74    else                        // other tasks busy-wait
75    {
76        while (*pcount != maxcount) asm volatile ("nop");
77    }
78}
79
Note: See TracBrowser for help on using the repository browser.