Rev 169 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 169 | Rev 171 | ||
|---|---|---|---|
| Line 15... | Line 15... | ||
| 15 | protocols.</para> |
15 | protocols.</para> |
| 16 | 16 | ||
| 17 | <section> |
17 | <section> |
| 18 | <title>Kernel Services</title> |
18 | <title>Kernel Services</title> |
| 19 | 19 | ||
| 20 | <para>Every message consists of four numeric arguments (32-bit and 64-bit on |
20 | <para>Every message consists of four numeric arguments (32-bit and 64-bit |
| 21 | the corresponding platforms), from which the first one is considered a |
21 | on the corresponding platforms), from which the first one is considered a |
| 22 | method number on message receipt and a return value on answer receipt. The |
22 | method number on message receipt and a return value on answer receipt. The |
| 23 | received message contains identification of the incoming connection, so |
23 | received message contains identification of the incoming connection, so |
| 24 | that the receiving application can distinguish the messages between |
24 | that the receiving application can distinguish the messages between |
| 25 | different senders. Internally the message contains pointer to the |
25 | different senders. Internally the message contains pointer to the |
| 26 | originating task and to the source of the communication channel. If the |
26 | originating task and to the source of the communication channel. If the |
| Line 99... | Line 99... | ||
| 99 | </mediaobject> |
99 | </mediaobject> |
| 100 | </figure> |
100 | </figure> |
| 101 | 101 | ||
| 102 | <para>The communication between task A, that is connected to task B |
102 | <para>The communication between task A, that is connected to task B |
| 103 | looks as follows: task A sends a message over its phone to the target |
103 | looks as follows: task A sends a message over its phone to the target |
| 104 | asnwerbox. The message is saved in task B's incoming call queue. When task |
104 | asnwerbox. The message is saved in task B's incoming call queue. When |
| 105 | B fetches the message for processing, it is automatically moved into the |
105 | task B fetches the message for processing, it is automatically moved |
| 106 | dispatched call queue. After the server decides to answer the message, |
106 | into the dispatched call queue. After the server decides to answer the |
| 107 | it is removed from dispatched queue and the result is moved into the |
107 | message, it is removed from dispatched queue and the result is moved |
| 108 | answer queue of task A.</para> |
108 | into the answer queue of task A.</para> |
| 109 | 109 | ||
| 110 | <para>The arguments contained in the message are completely arbitrary |
110 | <para>The arguments contained in the message are completely arbitrary |
| 111 | and decided by the user. The low level part of kernel IPC fills in |
111 | and decided by the user. The low level part of kernel IPC fills in |
| 112 | appropriate error codes if there is an error during communication. It is |
112 | appropriate error codes if there is an error during communication. It is |
| 113 | assured that the applications are correctly notified about communication |
113 | assured that the applications are correctly notified about communication |
| Line 117... | Line 117... | ||
| 117 | are answered.</para> |
117 | are answered.</para> |
| 118 | 118 | ||
| 119 | <para>Closing an incoming connection is done by responding to any |
119 | <para>Closing an incoming connection is done by responding to any |
| 120 | incoming message with an EHANGUP error code. The connection is then |
120 | incoming message with an EHANGUP error code. The connection is then |
| 121 | immediately closed. The client connection identification (phone id) is |
121 | immediately closed. The client connection identification (phone id) is |
| 122 | not reused, until the client closes its own side of the |
122 | not reused, until the client closes its own side of the connection |
| 123 | connection ("hangs his phone up").</para> |
123 | ("hangs his phone up").</para> |
| 124 | 124 | ||
| 125 | <para>When a task dies (whether voluntarily or by being killed), cleanup |
125 | <para>When a task dies (whether voluntarily or by being killed), cleanup |
| 126 | process is started.</para> |
126 | process is started.</para> |
| 127 | 127 | ||
| 128 | <orderedlist> |
128 | <orderedlist> |
| Line 155... | Line 155... | ||
| 155 | <title>System Call IPC Layer</title> |
155 | <title>System Call IPC Layer</title> |
| 156 | 156 | ||
| 157 | <para>On top of this simple protocol the kernel provides special |
157 | <para>On top of this simple protocol the kernel provides special |
| 158 | services closely related to the inter-process communication. A range of |
158 | services closely related to the inter-process communication. A range of |
| 159 | method numbers is allocated and protocol is defined for these functions. |
159 | method numbers is allocated and protocol is defined for these functions. |
| 160 | These messages are interpreted by the kernel layer and appropriate actions |
160 | These messages are interpreted by the kernel layer and appropriate |
| 161 | are taken depending on the parameters of the message and the answer.</para> |
161 | actions are taken depending on the parameters of the message and the |
| - | 162 | answer.</para> |
|
| 162 | 163 | ||
| 163 | <para>The kernel provides the following services:</para> |
164 | <para>The kernel provides the following services:</para> |
| 164 | 165 | ||
| 165 | <itemizedlist> |
166 | <itemizedlist> |
| 166 | <listitem> |
167 | <listitem> |
| Line 180... | Line 181... | ||
| 180 | </listitem> |
181 | </listitem> |
| 181 | </itemizedlist> |
182 | </itemizedlist> |
| 182 | 183 | ||
| 183 | <para>On startup, every task is automatically connected to a |
184 | <para>On startup, every task is automatically connected to a |
| 184 | <emphasis>naming service task</emphasis>, which provides a switchboard |
185 | <emphasis>naming service task</emphasis>, which provides a switchboard |
| 185 | functionality. In order to open a new outgoing connection, the client sends a |
186 | functionality. In order to open a new outgoing connection, the client |
| 186 | <constant>CONNECT_ME_TO</constant> message using any of his phones. If |
187 | sends a <constant>CONNECT_ME_TO</constant> message using any of his |
| 187 | the recepient of this message answers with an accepting answer, a new |
188 | phones. If the recepient of this message answers with an accepting |
| 188 | connection is created. In itself, this mechanism would allow only |
189 | answer, a new connection is created. In itself, this mechanism would |
| 189 | duplicating existing connection. However, if the message is forwarded, |
190 | allow only duplicating existing connection. However, if the message is |
| 190 | the new connection is made to the final recipient.</para> |
191 | forwarded, the new connection is made to the final recipient.</para> |
| 191 | 192 | ||
| 192 | <para>In order for a task to be able to forward a message, it |
193 | <para>In order for a task to be able to forward a message, it must have |
| 193 | must have a phone connected to the destination task. |
194 | a phone connected to the destination task. The destination task |
| 194 | The destination task establishes such connection by sending the <constant>CONNECT_TO_ME</constant> |
195 | establishes such connection by sending the |
| 195 | message to the forwarding task. A callback connection is opened afterwards. |
196 | <constant>CONNECT_TO_ME</constant> message to the forwarding task. A |
| 196 | Every service that wants to receive connections |
197 | callback connection is opened afterwards. Every service that wants to |
| 197 | has to ask the naming service to create the callback connection via this mechanism.</para> |
198 | receive connections has to ask the naming service to create the callback |
| - | 199 | connection via this mechanism.</para> |
|
| 198 | 200 | ||
| 199 | <para>Tasks can share their address space areas using IPC messages. The |
201 | <para>Tasks can share their address space areas using IPC messages. The |
| 200 | two message types - <constant>AS_AREA_SEND</constant> and <constant>AS_AREA_RECV</constant> are used for sending and |
202 | two message types - <constant>AS_AREA_SEND</constant> and |
| - | 203 | <constant>AS_AREA_RECV</constant> are used for sending and receiving an |
|
| 201 | receiving an address space area respectively. The shared area can be accessed |
204 | address space area respectively. The shared area can be accessed as soon |
| 202 | as soon as the message is acknowledged.</para> |
205 | as the message is acknowledged.</para> |
| 203 | </section> |
206 | </section> |
| 204 | </section> |
207 | </section> |
| 205 | 208 | ||
| 206 | <section> |
209 | <section> |
| 207 | <title>Userspace View</title> |
210 | <title>Userspace View</title> |
| 208 | 211 | ||
| 209 | <para>The conventional design of the asynchronous API seems to produce |
212 | <para>The conventional design of the asynchronous API seems to produce |
| 210 | applications with one event loop and several big switch statements. |
213 | applications with one event loop and several big switch statements. |
| 211 | However, by intensive utilization of userspace pseudo threads, it was possible |
214 | However, by intensive utilization of userspace fibrils, it was possible to |
| 212 | to create an environment that is not necessarily restricted to this type |
215 | create an environment that is not necessarily restricted to this type of |
| 213 | of event-driven programming and allows for more fluent expression of |
216 | event-driven programming and allows for more fluent expression of |
| 214 | application programs.</para> |
217 | application programs.</para> |
| 215 | 218 | ||
| 216 | <section> |
219 | <section> |
| 217 | <title>Single Point of Entry</title> |
220 | <title>Single Point of Entry</title> |
| 218 | 221 | ||
| 219 | <para>Each task is associated with only one answerbox. If a |
222 | <para>Each task is associated with only one answerbox. If a |
| 220 | multithreaded application needs to communicate, it must be not only |
223 | multithreaded application needs to communicate, it must be not only able |
| 221 | able to send a message, but it should be able to retrieve the answer as |
224 | to send a message, but it should be able to retrieve the answer as well. |
| 222 | well. If several pseudo threads pull messages from task answerbox, it is a |
225 | If several fibrils pull messages from task answerbox, it is a matter of |
| 223 | matter of coincidence, which thread receives which message. If a particular |
226 | coincidence, which fibril receives which message. If a particular fibril |
| 224 | thread needs to wait for a message answer, an idle |
227 | needs to wait for a message answer, an idle <emphasis>manager</emphasis> |
| 225 | <emphasis>manager</emphasis> pseudo thread is found or a new one is created and |
228 | fibril is found or a new one is created and control is transfered to |
| 226 | control is transfered to this manager thread. The manager threads pop |
229 | this manager fibril. The manager fibrils pop messages from the answerbox |
| 227 | messages from the answerbox and put them into appropriate queues of |
230 | and put them into appropriate queues of running fibrils. If a fibril |
| 228 | running threads. If a pseudo thread waiting for a message is not running, the |
231 | waiting for a message is not running, the control is transferred to |
| 229 | control is transferred to it.</para> |
232 | it.</para> |
| 230 | 233 | ||
| 231 | <figure float="1"> |
234 | <figure float="1"> |
| 232 | <title>Single point of entry</title> |
235 | <title>Single point of entry</title> |
| - | 236 | ||
| 233 | <mediaobject id="ipc2"> |
237 | <mediaobject id="ipc2"> |
| 234 | <imageobject role="pdf"> |
238 | <imageobject role="pdf"> |
| 235 | <imagedata fileref="images/ipc2.pdf" format="PDF" /> |
239 | <imagedata fileref="images/ipc2.pdf" format="PDF" /> |
| 236 | </imageobject> |
240 | </imageobject> |
| 237 | 241 | ||
| Line 241... | Line 245... | ||
| 241 | 245 | ||
| 242 | <imageobject role="fop"> |
246 | <imageobject role="fop"> |
| 243 | <imagedata fileref="images/ipc2.svg" format="SVG" /> |
247 | <imagedata fileref="images/ipc2.svg" format="SVG" /> |
| 244 | </imageobject> |
248 | </imageobject> |
| 245 | </mediaobject> |
249 | </mediaobject> |
| 246 | - | ||
| 247 | </figure> |
250 | </figure> |
| 248 | 251 | ||
| 249 | <para>Very similar situation arises when a task decides to send a lot of |
252 | <para>Very similar situation arises when a task decides to send a lot of |
| 250 | messages and reaches the kernel limit of asynchronous messages. In such |
253 | messages and reaches the kernel limit of asynchronous messages. In such |
| 251 | situation, two remedies are available - the userspace library can either |
254 | situation, two remedies are available - the userspace library can either |
| 252 | cache the message locally and resend the message when some answers |
255 | cache the message locally and resend the message when some answers |
| 253 | arrive, or it can block the thread and let it go on only after the |
256 | arrive, or it can block the fibril and let it go on only after the |
| 254 | message is finally sent to the kernel layer. With one exception, HelenOS |
257 | message is finally sent to the kernel layer. With one exception, HelenOS |
| 255 | uses the second approach - when the kernel responds that the maximum limit |
258 | uses the second approach - when the kernel responds that the maximum |
| 256 | of asynchronous messages was reached, the control is transferred to a manager |
259 | limit of asynchronous messages was reached, the control is transferred |
| 257 | pseudo thread. The manager thread then handles incoming replies and, when space |
260 | to a manager fibril. The manager fibril then handles incoming replies |
| 258 | is available, sends the message to the kernel and resumes the application thread |
261 | and, when space is available, sends the message to the kernel and |
| 259 | execution.</para> |
262 | resumes the application fibril execution.</para> |
| 260 | 263 | ||
| 261 | <para>If a kernel notification is received, the servicing procedure is |
264 | <para>If a kernel notification is received, the servicing procedure is |
| 262 | run in the context of the manager pseudo thread. Although it wouldn't be |
265 | run in the context of the manager fibril. Although it wouldn't be |
| 263 | impossible to allow recursive calling, it could potentially lead to an |
266 | impossible to allow recursive calling, it could potentially lead to an |
| 264 | explosion of manager threads. Thus, the kernel notification procedures |
267 | explosion of manager fibrils. Thus, the kernel notification procedures |
| 265 | are not allowed to wait for a message result, they can only answer |
268 | are not allowed to wait for a message result, they can only answer |
| 266 | messages and send new ones without waiting for their results. If the |
269 | messages and send new ones without waiting for their results. If the |
| 267 | kernel limit for outgoing messages is reached, the data is automatically |
270 | kernel limit for outgoing messages is reached, the data is automatically |
| 268 | cached within the application. This behaviour is enforced automatically |
271 | cached within the application. This behaviour is enforced automatically |
| 269 | and the decision making is hidden from the developer.</para> |
272 | and the decision making is hidden from the developer.</para> |
| 270 | 273 | ||
| 271 | <figure float="1"> |
274 | <figure float="1"> |
| 272 | <title>Single point of entry solution</title> |
275 | <title>Single point of entry solution</title> |
| - | 276 | ||
| 273 | <mediaobject id="ipc3"> |
277 | <mediaobject id="ipc3"> |
| 274 | <imageobject role="pdf"> |
278 | <imageobject role="pdf"> |
| 275 | <imagedata fileref="images/ipc3.pdf" format="PDF" /> |
279 | <imagedata fileref="images/ipc3.pdf" format="PDF" /> |
| 276 | </imageobject> |
280 | </imageobject> |
| 277 | 281 | ||
| Line 281... | Line 285... | ||
| 281 | 285 | ||
| 282 | <imageobject role="fop"> |
286 | <imageobject role="fop"> |
| 283 | <imagedata fileref="images/ipc3.svg" format="SVG" /> |
287 | <imagedata fileref="images/ipc3.svg" format="SVG" /> |
| 284 | </imageobject> |
288 | </imageobject> |
| 285 | </mediaobject> |
289 | </mediaobject> |
| 286 | - | ||
| 287 | </figure> |
290 | </figure> |
| 288 | </section> |
291 | </section> |
| 289 | 292 | ||
| 290 | <section> |
293 | <section> |
| 291 | <title>Ordering Problem</title> |
294 | <title>Ordering Problem</title> |
| Line 296... | Line 299... | ||
| 296 | start intervening. This can happen even if the application utilizes only |
299 | start intervening. This can happen even if the application utilizes only |
| 297 | one userspace thread. Classical synchronization using semaphores is not |
300 | one userspace thread. Classical synchronization using semaphores is not |
| 298 | possible as locking on them would block the thread completely so that |
301 | possible as locking on them would block the thread completely so that |
| 299 | the answer couldn't be ever processed. The IPC framework allows a |
302 | the answer couldn't be ever processed. The IPC framework allows a |
| 300 | developer to specify, that part of the code should not be preempted by |
303 | developer to specify, that part of the code should not be preempted by |
| 301 | any other pseudo thread (except notification handlers) while still being able |
304 | any other fibril (except notification handlers) while still being able |
| 302 | to queue messages belonging to other pseudo threads and regain control when the |
305 | to queue messages belonging to other fibrils and regain control when the |
| 303 | answer arrives.</para> |
306 | answer arrives.</para> |
| 304 | 307 | ||
| 305 | <para>This mechanism works transparently in multithreaded environment, |
308 | <para>This mechanism works transparently in multithreaded environment, |
| 306 | where additional locking mechanism (futexes) should be used. The IPC |
309 | where additional locking mechanism (futexes) should be used. The IPC |
| 307 | framework ensures that there will always be enough free userspace threads |
310 | framework ensures that there will always be enough free userspace |
| 308 | to handle incoming answers and allow the application to run more |
311 | threads to handle incoming answers and allow the application to run more |
| 309 | pseudo threads inside the usrspace threads without the danger of |
312 | fibrils inside the userspace threads without the danger of locking all |
| 310 | locking all userspace threads in futexes.</para> |
313 | userspace threads in futexes.</para> |
| 311 | </section> |
314 | </section> |
| 312 | 315 | ||
| 313 | <section> |
316 | <section> |
| 314 | <title>The Interface</title> |
317 | <title>The Interface</title> |
| 315 | 318 | ||
| Line 319... | Line 322... | ||
| 319 | the kernel limit, the flow of application is stopped until some answers |
322 | the kernel limit, the flow of application is stopped until some answers |
| 320 | arrive. On the other hand, server applications are expected to work in a |
323 | arrive. On the other hand, server applications are expected to work in a |
| 321 | multithreaded environment.</para> |
324 | multithreaded environment.</para> |
| 322 | 325 | ||
| 323 | <para>The server interface requires the developer to specify a |
326 | <para>The server interface requires the developer to specify a |
| 324 | <function>connection_thread</function> function. When new connection is |
327 | <function>connection_fibril</function> function. When new connection is |
| 325 | detected, a new pseudo thread is automatically created and control is |
328 | detected, a new fibril is automatically created and control is |
| 326 | transferred to this function. The code then decides whether to accept |
329 | transferred to this function. The code then decides whether to accept |
| 327 | the connection and creates a normal event loop. The userspace IPC |
330 | the connection and creates a normal event loop. The userspace IPC |
| 328 | library ensures correct switching between several pseudo threads |
331 | library ensures correct switching between several threads within the |
| 329 | within the kernel environment.</para> |
332 | kernel environment.</para> |
| 330 | </section> |
333 | </section> |
| 331 | </section> |
334 | </section> |
| 332 | </chapter> |
335 | </chapter> |
| 333 | 336 | ||