Nrk-api-signals-semaphores

Version 43 (Anthony Rowe, 04/03/2011 07:12 pm)

1 43 Anthony Rowe
2 43 Anthony Rowe
h1. Signals
3 43 Anthony Rowe
4 39 Anthony Rowe
[[TracNav(nrk-api-toc)]]
5 1 Anthony Rowe
A signal is a message that a task can use to wakeup one or more tasks waiting on an
6 1 Anthony Rowe
event or events. When waiting on an event, a task is suspended and does not consume
7 4 Anthony Rowe
CPU time. Nano-RK supports 32 unique signals. It is possible to wait on multiple
8 1 Anthony Rowe
signals such that any one of them can wake a task from sleep. All signals must be
9 6 Anthony Rowe
created using nrk_sig_create() before they can be used.  Any task that wishes to wakeup on a signal
10 1 Anthony Rowe
must register the signal using nrk_sig_register().  There are a few special case signals that are
11 1 Anthony Rowe
generated by the kernel used to support event timeouts and notification of special actions.  See the
12 43 Anthony Rowe
*Special Kernel Signals* subsection for more information.  For more information about signals, please refer
13 1 Anthony Rowe
to the basic_signals project that comes with Nano-RK: 
14 43 Anthony Rowe
"basic_signals":http://www.nanork.org/browser/nano-RK/projects/examples/signals
15 1 Anthony Rowe
16 1 Anthony Rowe
Each signal and semaphore requires a system resource.  These are statically defined and must be declared in the nrk_cfg.h file as shown below:
17 43 Anthony Rowe
<pre>
18 43 Anthony Rowe
<code class="c">
19 42 Anthony Rowe
#define NRK_MAX_RESOURCE_CNT       5
20 43 Anthony Rowe
</code></pre>
21 28 Anthony Rowe
22 43 Anthony Rowe
*Signal and Semaphore Types*
23 5 Anthony Rowe
24 43 Anthony Rowe
<pre>
25 43 Anthony Rowe
<code class="c">
26 1 Anthony Rowe
// This is a macro used to convert a signal into a bitmask for nrk_event_wait()
27 1 Anthony Rowe
// See nrk_event_wait() for an example.
28 1 Anthony Rowe
#define SIG(x)  ((uint32_t)1)<<x 
29 5 Anthony Rowe
30 5 Anthony Rowe
// These are typedefs used to represent signals and semaphores
31 5 Anthony Rowe
typedef int8_t nrk_sig_t;
32 1 Anthony Rowe
typedef uint32_t nrk_sig_mask_t;
33 5 Anthony Rowe
typedef int8_t nrk_sem_t;
34 43 Anthony Rowe
</code></pre>
35 36 Anthony Rowe
36 43 Anthony Rowe
37 43 Anthony Rowe
h3. nrk_signal_create
38 43 Anthony Rowe
39 1 Anthony Rowe
|| void nrk_signal_create() ||
40 43 Anthony Rowe
|| _Parameters_: none ||
41 43 Anthony Rowe
|| _Return Values:_ nrk_sig_t new signal id ||
42 1 Anthony Rowe
43 1 Anthony Rowe
This function creates a signal.  Upon failure, this function returns NRK_ERROR.  Upon success a positive value
44 1 Anthony Rowe
representing the signal is returned.
45 1 Anthony Rowe
46 43 Anthony Rowe
<pre>
47 1 Anthony Rowe
  nrk_sig_t signal_one;
48 1 Anthony Rowe
  nrk_sig_t signal_two;
49 1 Anthony Rowe
  ...
50 36 Anthony Rowe
                    
51 36 Anthony Rowe
  signal_one=nrk_signal_create();
52 1 Anthony Rowe
  signal_two=nrk_signal_create();
53 43 Anthony Rowe
</code></pre>
54 1 Anthony Rowe
55 43 Anthony Rowe
56 43 Anthony Rowe
h3. nrk_signal_delete
57 43 Anthony Rowe
58 1 Anthony Rowe
|| int8_t nrk_signal_delete(nrk_sig_t sig_id) ||
59 43 Anthony Rowe
|| _Parameters_: nrk_sig_t signal id of signal to remove ||
60 43 Anthony Rowe
|| _Return Values:_ int8_t NRK_OK upon success and NRK_ERROR upon failure ||
61 1 Anthony Rowe
62 43 Anthony Rowe
This function deletes a signal _sig_id_ so that it can be reused by different tasks.  This function returns NRK_OK upon success and NRK_ERROR on failure.
63 36 Anthony Rowe
64 43 Anthony Rowe
65 43 Anthony Rowe
h3. nrk_event_signal
66 43 Anthony Rowe
67 23 Anthony Rowe
|| int8_t nrk_event_signal(nrk_sig_t sig_id) ||
68 43 Anthony Rowe
|| _Parameters_: nrk_sig_t signal id of signal to be sent ||
69 43 Anthony Rowe
|| _Return Values:_ int8_t NRK_OK upon success and NRK_ERROR upon failure ||
70 1 Anthony Rowe
71 1 Anthony Rowe
This function is used to signal tasks that are waiting on events using nrk_event_wait().
72 43 Anthony Rowe
_sig_id_ is the signal that is sent.  This function returns NRK_OK upon success and NRK_ERROR upon failure.
73 31 Anthony Rowe
If a lower priority task signals a higher priority task, the high priority task will begin to execute at 
74 29 Anthony Rowe
the next context swap.  Normally this happens when the low priority task suspends, but it is also possible
75 29 Anthony Rowe
that a medium priority task could preempt the low priority task causing a context swap that would then
76 1 Anthony Rowe
schedule the waiting high priority task.  For this reason, processing that needs to be complete before the signaled task
77 24 Anthony Rowe
executes should be done before the signals are sent. 
78 43 Anthony Rowe
* Errno
79 43 Anthony Rowe
** 1 Signal was not created
80 43 Anthony Rowe
** 2 No task was waiting on signal
81 24 Anthony Rowe
82 43 Anthony Rowe
<pre>
83 43 Anthony Rowe
<code class="c">
84 1 Anthony Rowe
   v=nrk_event_signal( signal_one );
85 1 Anthony Rowe
   if(v==NRK_ERROR) nrk_kprintf( PSTR( "nrk_event_signal failed\r\n" ));
86 43 Anthony Rowe
</code></pre>
87 1 Anthony Rowe
88 43 Anthony Rowe
89 43 Anthony Rowe
h3. nrk_event_wait
90 43 Anthony Rowe
91 1 Anthony Rowe
|| nrk_sig_mask_t nrk_event_signal(nrk_sig_mask_t event_mask) ||
92 43 Anthony Rowe
|| _Parameters_: nrk_sig_mask_t event mask of signal to wait on, use SIG() macro with signal value ||
93 43 Anthony Rowe
|| _Return Values:_ nrk_sig_mask_t signal mask that triggered wakeup ||
94 1 Anthony Rowe
95 24 Anthony Rowe
This function will wait for a set events. nano-RK supports up to 32 signals. Each signal
96 1 Anthony Rowe
represents a bit in a 32 bit number so it is possible to logically
97 1 Anthony Rowe
OR multiple signals together if you wish to wait on a combination of events. The 32
98 24 Anthony Rowe
bit number returned by nrk_event_wait() corresponds to the signal or signals that were returned.
99 1 Anthony Rowe
When waiting on multiple signals, the return value can be used to determine which signal
100 24 Anthony Rowe
triggered the wakeup. All signals need to be registered in order for a task to receive them.
101 24 Anthony Rowe
This function returns 0 upon failure if a signal is specified that does not exist, or is not
102 24 Anthony Rowe
registered.
103 1 Anthony Rowe
104 43 Anthony Rowe
<pre>
105 43 Anthony Rowe
<code class="c">
106 24 Anthony Rowe
  nrk_sig_mask_t my_sigs;
107 24 Anthony Rowe
  int8_t v;
108 24 Anthony Rowe
109 24 Anthony Rowe
  // Don't forget to register signal for reception
110 24 Anthony Rowe
  v=nrk_signal_register(signal_one);
111 1 Anthony Rowe
  if(v==NRK_ERROR) nrk_kprintf( PSTR( "nrk_signal_register failed\r\n" ));
112 1 Anthony Rowe
  v=nrk_signal_register(signal_two);
113 1 Anthony Rowe
  if(v==NRK_ERROR) nrk_kprintf( PSTR( "nrk_signal_register failed\r\n" ));
114 1 Anthony Rowe
115 1 Anthony Rowe
  ...
116 1 Anthony Rowe
  // Waiting on signal_one OR signal_two
117 23 Anthony Rowe
  my_sigs=nrk_event_wait( SIG(signal_one) | SIG(signal_two) );
118 24 Anthony Rowe
119 24 Anthony Rowe
  if(my_sigs==0) nrk_kprintf( PSTR( "nrk_event_wait failed\r\n" ));
120 1 Anthony Rowe
  if(my_sigs & SIG(signal_one))
121 23 Anthony Rowe
     nrk_kprintf( PSTR( "Task got signal 1\r\n") );
122 23 Anthony Rowe
  if(my_sigs & SIG(signal_two))
123 1 Anthony Rowe
     nrk_kprintf( PSTR( "Task got timeout signal2\r\n") );
124 43 Anthony Rowe
</code></pre>
125 1 Anthony Rowe
126 43 Anthony Rowe
*int8_t nrk_signal_register(nrk_sig_t sig_id);*
127 1 Anthony Rowe
128 43 Anthony Rowe
This function registers a signal _sig_id_ so that a task is able to receive it.  This function returns NRK_OK upon success and NRK_ERROR upon failure if the signal does not exist.  A signal only needs to be registered for reception and not transmission.
129 1 Anthony Rowe
130 43 Anthony Rowe
<pre>
131 43 Anthony Rowe
<code class="c">
132 1 Anthony Rowe
  v=nrk_signal_register(signal_two);
133 11 Anthony Rowe
  if(v==NRK_ERROR) nrk_kprintf( PSTR( "Error calling nrk_signal_register\r\n" ));
134 43 Anthony Rowe
</code></pre>
135 12 Anthony Rowe
136 1 Anthony Rowe
137 43 Anthony Rowe
*int8_t nrk_signal_unregister(nrk_sig_t sig_id);*
138 1 Anthony Rowe
139 43 Anthony Rowe
This function unregisters a signal _sig_id_ so that the task is no longer able to be unsuspended by that event.  This function returns NRK_OK upon success and NRK_ERROR uopn failure.
140 1 Anthony Rowe
141 10 Anthony Rowe
142 43 Anthony Rowe
*nrk_sig_mask_t nrk_signal_get_registered_mask();*
143 1 Anthony Rowe
144 10 Anthony Rowe
This function returns the current registered signal mask for a task.
145 1 Anthony Rowe
146 1 Anthony Rowe
147 43 Anthony Rowe
h1. Semaphores
148 43 Anthony Rowe
149 43 Anthony Rowe
150 10 Anthony Rowe
A semaphore is a protected variable and constitutes the classic method for restricting
151 1 Anthony Rowe
access to shared resources (e.g. storage,actuators etc) in a multiprogramming environment.
152 1 Anthony Rowe
Nano-RK implements semaphores and signals such that
153 1 Anthony Rowe
tasks that are suspended on an event or waiting for access to a semaphore will not be
154 10 Anthony Rowe
scheduled until the corresponding signal is sent or semaphore becomes available. For more information
155 1 Anthony Rowe
on using semaphores please refer to the basic_sem project that comes with the Nano-RK distribution: 
156 43 Anthony Rowe
"basic_sem":http://www.nanork.org/browser/nano-RK/projects/basic_sem/main.c
157 10 Anthony Rowe
158 43 Anthony Rowe
_Note that the Atmel ISA does not have a test-and-set instruction, so we provide a best effort implementation by disabling interrupts._ 
159 1 Anthony Rowe
160 43 Anthony Rowe
*nrk_sem_t* nrk_sem_create(uint8_t count, uint8_t ceiling_priority);*
161 1 Anthony Rowe
162 43 Anthony Rowe
This function creates a semaphore resource, with a priority ceiling value used by the task when accessing the resource. This facilitates the Priority Ceiling Protocol Emulation (PCPE) algorithm used in Nano-RK to avoid priority inversion. _count_ specifies the number of entries allowed into the critical section. _ceiling_priority_ sets the ceiling value for the task; Note if
163 37 Anthony Rowe
using PCPE this should be the highest priority task accessing the critical section.  Below is an example of declaring and creating a semaphore:
164 37 Anthony Rowe
165 43 Anthony Rowe
<pre>
166 43 Anthony Rowe
<code class="c">
167 37 Anthony Rowe
   nrk_sem_t *my_semaphore;
168 37 Anthony Rowe
   ...
169 37 Anthony Rowe
   my_semaphore = nrk_sem_create(1,4);
170 37 Anthony Rowe
   if(my_semaphore==NULL) nrk_kprintf( PSTR("Error creating Semaphore\r\n" ));
171 43 Anthony Rowe
</code></pre>
172 1 Anthony Rowe
173 1 Anthony Rowe
This created a semaphore with a count of 1 (also called a mutex or binary semaphore) with a priority ceiling value of 4.
174 8 Anthony Rowe
175 43 Anthony Rowe
*int8_t nrk_sem_delete(nrk_sem_t *rsrc );* 
176 8 Anthony Rowe
177 1 Anthony Rowe
This function deletes an existing semaphore which will free the resource for reuse.  This function returns NRK_OK upon success and NRK_ERROR on failure.  Errno is set depending on the error type:
178 43 Anthony Rowe
* Errno
179 43 Anthony Rowe
** 1 Signal Not Found
180 43 Anthony Rowe
** 2 Signal Index too large
181 1 Anthony Rowe
182 1 Anthony Rowe
183 43 Anthony Rowe
*int8_t nrk_sem_pend(nrk_sem_t *rsrc );* 
184 1 Anthony Rowe
185 1 Anthony Rowe
Semaphore pend takes the address of the created semaphore and attempts to access the resource.  If the resource is available,
186 1 Anthony Rowe
pend will decrement the resource counter and allow the program to continue, otherwise pend will suspend until the resource is
187 9 Anthony Rowe
posted by another task. This can be used to protect critical sections of code. Below is an example of a task pending on a semaphore:
188 43 Anthony Rowe
* Errno
189 43 Anthony Rowe
** 1 Signal Not Found
190 43 Anthony Rowe
** 2 Signal Index too large
191 9 Anthony Rowe
192 43 Anthony Rowe
<pre>
193 43 Anthony Rowe
<code class="c">
194 31 Anthony Rowe
   nrk_kprintf( PSTR("Task accessing semaphore\r\n"));
195 30 Anthony Rowe
   v = nrk_sem_pend(my_semaphore);
196 30 Anthony Rowe
   if(v==NRK_ERROR) nrk_kprintf( PSTR("Error calling pend\r\n"));
197 9 Anthony Rowe
   nrk_kprintf( PSTR("Task is now holding semaphore\r\n"));
198 43 Anthony Rowe
</code></pre>
199 9 Anthony Rowe
200 43 Anthony Rowe
*int8_t nrk_sem_post(nrk_sem_t* rsrc);*
201 8 Anthony Rowe
202 8 Anthony Rowe
Semaphore post takes the address of a created semaphore and releases access to the resource.
203 11 Anthony Rowe
This should be called after exiting a critical section that was pended.  Below is an example of a task posting a semaphore:
204 43 Anthony Rowe
* Errno
205 43 Anthony Rowe
** 1 Signal Not Found
206 43 Anthony Rowe
** 2 Signal Index too large
207 43 Anthony Rowe
<pre>
208 43 Anthony Rowe
<code class="c">
209 34 Anthony Rowe
   v = nrk_sem_post(my_semaphore);
210 34 Anthony Rowe
   if(v==NRK_ERROR) nrk_kprintf( PSTR("Error calling post\r\n"));
211 34 Anthony Rowe
   nrk_kprintf( PSTR("Task released semaphore\r\n"));
212 43 Anthony Rowe
</code></pre>
213 8 Anthony Rowe
214 18 Anthony Rowe
215 43 Anthony Rowe
*int8_t nrk_sem_query(nrk_sem_t *rsrc );* 
216 19 Anthony Rowe
217 33 Anthony Rowe
This returns the current count value of the semaphore.  This can be used to check if the semaphore will allow access without actually trying to lock it.
218 43 Anthony Rowe
* Errno
219 43 Anthony Rowe
** 1 Signal Not Found
220 43 Anthony Rowe
** 2 Signal Index too large
221 19 Anthony Rowe
222 18 Anthony Rowe
223 17 Anthony Rowe
224 43 Anthony Rowe
h1. Special Kernel Signals
225 17 Anthony Rowe
226 43 Anthony Rowe
227 43 Anthony Rowe
*nrk_wakeup_signal*
228 43 Anthony Rowe
229 1 Anthony Rowe
Sometimes it might be convenient to have a timeout associated with an nrk_event_wait() call.   This can be achieved using the kernel generated nrk_wakeup_signal.  This signal is sent on a per-task basis (not globally) when the task’s internal next-wakeup timer expires.  Normally, a task’s next wakeup is set for its next period, however this can be adjusted using the nrk_set_next_wakeup() function. nrk_wakeup_signal is created by the kernel during nrk_init().  In order for nrk_event_wait() to receive the nrk_wakeup_signal from a task it must simply be registered and muxed in like any other signal.  Note, each task has its own instance of the nrk_wakeup_signal.  Unlike other signals, nrk_wakeup_signal is not globally broadcast to all tasks.  See below for an example of how to use it as an event  timeout.
230 1 Anthony Rowe
231 43 Anthony Rowe
*int8_t nrk_set_next_wakeup(nrk_time_t timeout);*
232 17 Anthony Rowe
233 17 Anthony Rowe
This function sets the task's next wakeup timer.  It returns NRK_OK upon success and NRK_ERROR on failure.  This function does not
234 21 Anthony Rowe
suspend the task, it only changes when the next wakeup will happen if the task suspends on an event.  Calling other suspend functions like nrk_wait_until_next_period() will replace whatever wakeup value you might have previously set. 
235 18 Anthony Rowe
236 43 Anthony Rowe
<pre>
237 43 Anthony Rowe
<code class="c">
238 17 Anthony Rowe
   nrk_time_t timeout;
239 1 Anthony Rowe
240 1 Anthony Rowe
   timeout.secs=10;
241 1 Anthony Rowe
   timeout.nano_secs=0;
242 1 Anthony Rowe
   ...
243 1 Anthony Rowe
244 1 Anthony Rowe
   nrk_set_next_wakeup(timeout);
245 1 Anthony Rowe
   my_sigs=nrk_event_wait( SIG(signal_one) | SIG(nrk_wakeup_signal) );
246 1 Anthony Rowe
247 1 Anthony Rowe
   // Lets check which signal we got...
248 1 Anthony Rowe
   if(my_sigs==0)                        nrk_kprintf( PSTR( "Error calling nrk_event_wait()\r\n" ));
249 1 Anthony Rowe
   if(my_sigs & SIG(signal_one))         nrk_kprintf( PSTR( "Task got signal_one\r\n") );
250 1 Anthony Rowe
   if(my_sigs & SIG(nrk_wakeup_signal))  nrk_kprintf( PSTR( "Task got timeout signal! \r\n") );
251 43 Anthony Rowe
</code></pre>
252 1 Anthony Rowe
253 43 Anthony Rowe
| [[nrk-api|Contents]  [wikinrk-api-device-drivers Device Drivers]] |