Subversion Repositories HelenOS

Rev

Rev 3424 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3424 Rev 4377
Line 28... Line 28...
28
 
28
 
29
/** @addtogroup libc
29
/** @addtogroup libc
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
 
34
 
35
/**
35
/**
36
 * Asynchronous library
36
 * Asynchronous library
37
 *
37
 *
38
 * The aim of this library is facilitating writing programs utilizing the
38
 * The aim of this library is to provide a facility for writing programs which
39
 * asynchronous nature of HelenOS IPC, yet using a normal way of programming.
39
 * utilize the asynchronous nature of HelenOS IPC, yet using a normal way of
-
 
40
 * programming.
40
 *
41
 *
41
 * You should be able to write very simple multithreaded programs, the async
42
 * You should be able to write very simple multithreaded programs, the async
42
 * framework will automatically take care of most synchronization problems.
43
 * framework will automatically take care of most synchronization problems.
43
 *
44
 *
44
 * Default semantics:
45
 * Default semantics:
45
 * - async_send_*():    send asynchronously. If the kernel refuses to send
46
 * - async_send_*(): Send asynchronously. If the kernel refuses to send
46
 *          more messages, [ try to get responses from kernel, if
47
 *                   more messages, [ try to get responses from kernel, if
47
 *          nothing found, might try synchronous ]
48
 *                   nothing found, might try synchronous ]
48
 *
49
 *
49
 * Example of use (pseudo C):
50
 * Example of use (pseudo C):
50
 *
51
 *
51
 * 1) Multithreaded client application
52
 * 1) Multithreaded client application
52
 *
53
 *
53
 * fibril_create(fibril1, ...);
54
 *   fibril_create(fibril1, ...);
54
 * fibril_create(fibril2, ...);
55
 *   fibril_create(fibril2, ...);
55
 * ...
56
 *   ...
56
 *  
57
 *
57
 * int fibril1(void *arg)
58
 *   int fibril1(void *arg)
58
 * {
59
 *   {
59
 *  conn = ipc_connect_me_to();
60
 *     conn = ipc_connect_me_to();
60
 *  c1 = async_send(conn);
61
 *     c1 = async_send(conn);
61
 *  c2 = async_send(conn);
62
 *     c2 = async_send(conn);
62
 *  async_wait_for(c1);
63
 *     async_wait_for(c1);
63
 *  async_wait_for(c2);
64
 *     async_wait_for(c2);
64
 *  ...
65
 *     ...
65
 * }
66
 *   }
66
 *
67
 *
67
 *
68
 *
68
 * 2) Multithreaded server application
69
 * 2) Multithreaded server application
-
 
70
 *
69
 * main()
71
 *   main()
70
 * {
72
 *   {
71
 *  async_manager();
73
 *     async_manager();
72
 * }
74
 *   }
73
 *
-
 
74
 *
75
 *
75
 * my_client_connection(icallid, *icall)
76
 *   my_client_connection(icallid, *icall)
76
 * {
77
 *   {
77
 *  if (want_refuse) {
78
 *     if (want_refuse) {
78
 *      ipc_answer_0(icallid, ELIMIT);
79
 *       ipc_answer_0(icallid, ELIMIT);
79
 *      return;
80
 *       return;
80
 *  }
81
 *     }
81
 *  ipc_answer_0(icallid, EOK);
82
 *     ipc_answer_0(icallid, EOK);
82
 *
83
 *
83
 *  callid = async_get_call(&call);
84
 *     callid = async_get_call(&call);
84
 *  handle_call(callid, call);
85
 *     handle_call(callid, call);
85
 *  ipc_answer_2(callid, 1, 2, 3);
86
 *     ipc_answer_2(callid, 1, 2, 3);
86
 *
87
 *
87
 *  callid = async_get_call(&call);
88
 *     callid = async_get_call(&call);
88
 *  ....
89
 *     ...
89
 * }
90
 *   }
90
 *
91
 *
91
 */
92
 */
92
 
93
 
93
#include <futex.h>
94
#include <futex.h>
94
#include <async.h>
95
#include <async.h>
Line 102... Line 103...
102
#include <sys/time.h>
103
#include <sys/time.h>
103
#include <arch/barrier.h>
104
#include <arch/barrier.h>
104
#include <bool.h>
105
#include <bool.h>
105
 
106
 
106
atomic_t async_futex = FUTEX_INITIALIZER;
107
atomic_t async_futex = FUTEX_INITIALIZER;
107
static hash_table_t conn_hash_table;
-
 
108
static LIST_INITIALIZE(timeout_list);
-
 
109
 
108
 
110
/** Structures of this type represent a waiting fibril. */
109
/** Structures of this type represent a waiting fibril. */
111
typedef struct {
110
typedef struct {
112
    /** Expiration time. */
111
    /** Expiration time. */
113
    struct timeval expires;    
112
    struct timeval expires;
-
 
113
   
114
    /** If true, this struct is in the timeout list. */
114
    /** If true, this struct is in the timeout list. */
115
    int inlist;
115
    bool inlist;
-
 
116
   
116
    /** Timeout list link. */
117
    /** Timeout list link. */
117
    link_t link;
118
    link_t link;
118
 
119
   
119
    /** Identification of and link to the waiting fibril. */
120
    /** Identification of and link to the waiting fibril. */
120
    fid_t fid;
121
    fid_t fid;
-
 
122
   
121
    /** If true, this fibril is currently active. */
123
    /** If true, this fibril is currently active. */
122
    int active;
124
    bool active;
-
 
125
   
123
    /** If true, we have timed out. */
126
    /** If true, we have timed out. */
124
    int timedout;
127
    bool timedout;
125
} awaiter_t;
128
} awaiter_t;
126
 
129
 
127
typedef struct {
130
typedef struct {
128
    awaiter_t wdata;
131
    awaiter_t wdata;
129
   
132
   
130
    /** If reply was received. */
133
    /** If reply was received. */
131
    int done;
134
    bool done;
-
 
135
   
132
    /** Pointer to where the answer data is stored. */
136
    /** Pointer to where the answer data is stored. */
133
    ipc_call_t *dataptr;
137
    ipc_call_t *dataptr;
134
 
138
   
135
    ipcarg_t retval;
139
    ipcarg_t retval;
136
} amsg_t;
140
} amsg_t;
137
 
141
 
138
/**
142
/**
139
 * Structures of this type are used to group information about a call and a
143
 * Structures of this type are used to group information about a call and a
Line 145... Line 149...
145
    ipc_call_t call;
149
    ipc_call_t call;
146
} msg_t;
150
} msg_t;
147
 
151
 
148
typedef struct {
152
typedef struct {
149
    awaiter_t wdata;
153
    awaiter_t wdata;
150
 
154
   
151
    /** Hash table link. */
155
    /** Hash table link. */
152
    link_t link;
156
    link_t link;
153
 
157
   
154
    /** Incoming phone hash. */
158
    /** Incoming phone hash. */
155
    ipcarg_t in_phone_hash;    
159
    ipcarg_t in_phone_hash;
156
 
160
   
157
    /** Messages that should be delivered to this fibril. */
161
    /** Messages that should be delivered to this fibril. */
158
    link_t msg_queue;      
162
    link_t msg_queue;
159
                     
163
   
160
    /** Identification of the opening call. */
164
    /** Identification of the opening call. */
161
    ipc_callid_t callid;
165
    ipc_callid_t callid;
162
    /** Call data of the opening call. */
166
    /** Call data of the opening call. */
163
    ipc_call_t call;
167
    ipc_call_t call;
164
 
168
   
165
    /** Identification of the closing call. */
169
    /** Identification of the closing call. */
166
    ipc_callid_t close_callid;
170
    ipc_callid_t close_callid;
167
 
171
   
168
    /** Fibril function that will be used to handle the connection. */
172
    /** Fibril function that will be used to handle the connection. */
169
    void (*cfibril)(ipc_callid_t, ipc_call_t *);
173
    void (*cfibril)(ipc_callid_t, ipc_call_t *);
170
} connection_t;
174
} connection_t;
171
 
175
 
172
/** Identifier of the incoming connection handled by the current fibril. */
176
/** Identifier of the incoming connection handled by the current fibril. */
173
__thread connection_t *FIBRIL_connection;
177
__thread connection_t *FIBRIL_connection;
174
 
178
 
175
/**
-
 
176
 * If true, it is forbidden to use async_req functions and all preemption is
-
 
177
 * disabled.
-
 
178
 */
-
 
179
__thread int _in_interrupt_handler;
-
 
180
 
-
 
181
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call);
179
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call);
182
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call);
180
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call);
183
 
181
 
184
/**
182
/**
185
 * Pointer to a fibril function that will be used to handle connections.
183
 * Pointer to a fibril function that will be used to handle connections.
186
 */
184
 */
187
static async_client_conn_t client_connection = default_client_connection;
185
static async_client_conn_t client_connection = default_client_connection;
-
 
186
 
188
/**
187
/**
189
 * Pointer to a fibril function that will be used to handle interrupt
188
 * Pointer to a fibril function that will be used to handle interrupt
190
 * notifications.
189
 * notifications.
191
 */
190
 */
192
static async_client_conn_t interrupt_received = default_interrupt_received;
191
static async_client_conn_t interrupt_received = default_interrupt_received;
193
 
192
 
194
/*
-
 
195
 * Getter for _in_interrupt_handler. We need to export the value of this thread
-
 
196
 * local variable to other modules, but the binutils 2.18 linkers die on an
-
 
197
 * attempt to export this symbol in the header file. For now, consider this as a
-
 
198
 * workaround.
-
 
199
 */
-
 
200
bool in_interrupt_handler(void)
-
 
201
{
-
 
202
    return _in_interrupt_handler;
-
 
203
}
-
 
204
 
193
 
-
 
194
static hash_table_t conn_hash_table;
-
 
195
static LIST_INITIALIZE(timeout_list);
-
 
196
 
-
 
197
 
205
#define CONN_HASH_TABLE_CHAINS  32
198
#define CONN_HASH_TABLE_CHAINS  32
206
 
199
 
207
/** Compute hash into the connection hash table based on the source phone hash.
200
/** Compute hash into the connection hash table based on the source phone hash.
208
 *
201
 *
209
 * @param key       Pointer to source phone hash.
202
 * @param key Pointer to source phone hash.
-
 
203
 *
-
 
204
 * @return Index into the connection hash table.
210
 *
205
 *
211
 * @return      Index into the connection hash table.
-
 
212
 */
206
 */
213
static hash_index_t conn_hash(unsigned long *key)
207
static hash_index_t conn_hash(unsigned long *key)
214
{
208
{
215
    assert(key);
209
    assert(key);
216
    return ((*key) >> 4) % CONN_HASH_TABLE_CHAINS;
210
    return (((*key) >> 4) % CONN_HASH_TABLE_CHAINS);
217
}
211
}
218
 
212
 
219
/** Compare hash table item with a key.
213
/** Compare hash table item with a key.
220
 *
214
 *
221
 * @param key       Array containing the source phone hash as the only item.
215
 * @param key  Array containing the source phone hash as the only item.
222
 * @param keys      Expected 1 but ignored.
216
 * @param keys Expected 1 but ignored.
223
 * @param item      Connection hash table item.
217
 * @param item Connection hash table item.
-
 
218
 *
-
 
219
 * @return True on match, false otherwise.
224
 *
220
 *
225
 * @return      True on match, false otherwise.
-
 
226
 */
221
 */
227
static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
222
static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
228
{
223
{
229
    connection_t *hs;
-
 
230
 
-
 
231
    hs = hash_table_get_instance(item, connection_t, link);
224
    connection_t *hs = hash_table_get_instance(item, connection_t, link);
232
   
-
 
233
    return key[0] == hs->in_phone_hash;
225
    return (key[0] == hs->in_phone_hash);
234
}
226
}
235
 
227
 
236
/** Connection hash table removal callback function.
228
/** Connection hash table removal callback function.
237
 *
229
 *
238
 * This function is called whenever a connection is removed from the connection
230
 * This function is called whenever a connection is removed from the connection
239
 * hash table.
231
 * hash table.
240
 *
232
 *
241
 * @param item      Connection hash table item being removed.
233
 * @param item Connection hash table item being removed.
-
 
234
 *
242
 */
235
 */
243
static void conn_remove(link_t *item)
236
static void conn_remove(link_t *item)
244
{
237
{
245
    free(hash_table_get_instance(item, connection_t, link));
238
    free(hash_table_get_instance(item, connection_t, link));
246
}
239
}
Line 253... Line 246...
253
    .remove_callback = conn_remove
246
    .remove_callback = conn_remove
254
};
247
};
255
 
248
 
256
/** Sort in current fibril's timeout request.
249
/** Sort in current fibril's timeout request.
257
 *
250
 *
258
 * @param wd        Wait data of the current fibril.
251
 * @param wd Wait data of the current fibril.
-
 
252
 *
259
 */
253
 */
260
static void insert_timeout(awaiter_t *wd)
254
static void insert_timeout(awaiter_t *wd)
261
{
255
{
262
    link_t *tmp;
-
 
263
    awaiter_t *cur;
-
 
264
 
-
 
265
    wd->timedout = 0;
256
    wd->timedout = false;
266
    wd->inlist = 1;
257
    wd->inlist = true;
267
 
258
   
268
    tmp = timeout_list.next;
259
    link_t *tmp = timeout_list.next;
269
    while (tmp != &timeout_list) {
260
    while (tmp != &timeout_list) {
270
        cur = list_get_instance(tmp, awaiter_t, link);
261
        awaiter_t *cur = list_get_instance(tmp, awaiter_t, link);
-
 
262
       
271
        if (tv_gteq(&cur->expires, &wd->expires))
263
        if (tv_gteq(&cur->expires, &wd->expires))
272
            break;
264
            break;
-
 
265
       
273
        tmp = tmp->next;
266
        tmp = tmp->next;
274
    }
267
    }
-
 
268
   
275
    list_append(&wd->link, tmp);
269
    list_append(&wd->link, tmp);
276
}
270
}
277
 
271
 
278
/** Try to route a call to an appropriate connection fibril.
272
/** Try to route a call to an appropriate connection fibril.
279
 *
273
 *
280
 * If the proper connection fibril is found, a message with the call is added to
274
 * If the proper connection fibril is found, a message with the call is added to
281
 * its message queue. If the fibril was not active, it is activated and all
275
 * its message queue. If the fibril was not active, it is activated and all
282
 * timeouts are unregistered.
276
 * timeouts are unregistered.
283
 *
277
 *
284
 * @param callid    Hash of the incoming call.
278
 * @param callid Hash of the incoming call.
285
 * @param call      Data of the incoming call.
279
 * @param call   Data of the incoming call.
286
 *
280
 *
287
 * @return      Zero if the call doesn't match any connection.
281
 * @return False if the call doesn't match any connection.
288
 *          One if the call was passed to the respective connection
282
 *         True if the call was passed to the respective connection fibril.
289
 *          fibril.
283
 *
290
 */
284
 */
291
static int route_call(ipc_callid_t callid, ipc_call_t *call)
285
static bool route_call(ipc_callid_t callid, ipc_call_t *call)
292
{
286
{
293
    connection_t *conn;
-
 
294
    msg_t *msg;
-
 
295
    link_t *hlp;
-
 
296
    unsigned long key;
-
 
297
 
-
 
298
    futex_down(&async_futex);
287
    futex_down(&async_futex);
299
 
288
   
300
    key = call->in_phone_hash;
289
    unsigned long key = call->in_phone_hash;
301
    hlp = hash_table_find(&conn_hash_table, &key);
290
    link_t *hlp = hash_table_find(&conn_hash_table, &key);
-
 
291
   
302
    if (!hlp) {
292
    if (!hlp) {
303
        futex_up(&async_futex);
293
        futex_up(&async_futex);
304
        return 0;
294
        return false;
305
    }
295
    }
-
 
296
   
306
    conn = hash_table_get_instance(hlp, connection_t, link);
297
    connection_t *conn = hash_table_get_instance(hlp, connection_t, link);
307
 
298
   
308
    msg = malloc(sizeof(*msg));
299
    msg_t *msg = malloc(sizeof(*msg));
-
 
300
    if (!msg) {
-
 
301
        futex_up(&async_futex);
-
 
302
        return false;
-
 
303
    }
-
 
304
   
309
    msg->callid = callid;
305
    msg->callid = callid;
310
    msg->call = *call;
306
    msg->call = *call;
311
    list_append(&msg->link, &conn->msg_queue);
307
    list_append(&msg->link, &conn->msg_queue);
312
 
308
   
313
    if (IPC_GET_METHOD(*call) == IPC_M_PHONE_HUNGUP)
309
    if (IPC_GET_METHOD(*call) == IPC_M_PHONE_HUNGUP)
314
        conn->close_callid = callid;
310
        conn->close_callid = callid;
315
   
311
   
316
    /* If the connection fibril is waiting for an event, activate it */
312
    /* If the connection fibril is waiting for an event, activate it */
317
    if (!conn->wdata.active) {
313
    if (!conn->wdata.active) {
-
 
314
       
318
        /* If in timeout list, remove it */
315
        /* If in timeout list, remove it */
319
        if (conn->wdata.inlist) {
316
        if (conn->wdata.inlist) {
320
            conn->wdata.inlist = 0;
317
            conn->wdata.inlist = false;
321
            list_remove(&conn->wdata.link);
318
            list_remove(&conn->wdata.link);
322
        }
319
        }
-
 
320
       
323
        conn->wdata.active = 1;
321
        conn->wdata.active = true;
324
        fibril_add_ready(conn->wdata.fid);
322
        fibril_add_ready(conn->wdata.fid);
325
    }
323
    }
326
 
324
   
327
    futex_up(&async_futex);
325
    futex_up(&async_futex);
-
 
326
    return true;
-
 
327
}
-
 
328
 
-
 
329
/** Notification fibril.
-
 
330
 *
-
 
331
 * When a notification arrives, a fibril with this implementing function is
-
 
332
 * created. It calls interrupt_received() and does the final cleanup.
-
 
333
 *
-
 
334
 * @param arg Message structure pointer.
-
 
335
 *
-
 
336
 * @return Always zero.
-
 
337
 *
-
 
338
 */
-
 
339
static int notification_fibril(void *arg)
-
 
340
{
-
 
341
    msg_t *msg = (msg_t *) arg;
-
 
342
    interrupt_received(msg->callid, &msg->call);
-
 
343
   
-
 
344
    free(msg);
-
 
345
    return 0;
-
 
346
}
328
 
347
 
-
 
348
/** Process interrupt notification.
-
 
349
 *
-
 
350
 * A new fibril is created which would process the notification.
-
 
351
 *
-
 
352
 * @param callid Hash of the incoming call.
-
 
353
 * @param call   Data of the incoming call.
-
 
354
 *
-
 
355
 * @return False if an error occured.
-
 
356
 *         True if the call was passed to the notification fibril.
-
 
357
 *
-
 
358
 */
-
 
359
static bool process_notification(ipc_callid_t callid, ipc_call_t *call)
-
 
360
{
-
 
361
    futex_down(&async_futex);
-
 
362
   
-
 
363
    msg_t *msg = malloc(sizeof(*msg));
-
 
364
    if (!msg) {
-
 
365
        futex_up(&async_futex);
-
 
366
        return false;
-
 
367
    }
-
 
368
   
-
 
369
    msg->callid = callid;
-
 
370
    msg->call = *call;
-
 
371
   
-
 
372
    fid_t fid = fibril_create(notification_fibril, msg);
-
 
373
    fibril_add_ready(fid);
-
 
374
   
-
 
375
    futex_up(&async_futex);
329
    return 1;
376
    return true;
330
}
377
}
331
 
378
 
332
/** Return new incoming message for the current (fibril-local) connection.
379
/** Return new incoming message for the current (fibril-local) connection.
333
 *
380
 *
334
 * @param call      Storage where the incoming call data will be stored.
381
 * @param call  Storage where the incoming call data will be stored.
335
 * @param usecs     Timeout in microseconds. Zero denotes no timeout.
382
 * @param usecs Timeout in microseconds. Zero denotes no timeout.
-
 
383
 *
-
 
384
 * @return If no timeout was specified, then a hash of the
-
 
385
 *         incoming call is returned. If a timeout is specified,
-
 
386
 *         then a hash of the incoming call is returned unless
-
 
387
 *         the timeout expires prior to receiving a message. In
-
 
388
 *         that case zero is returned.
336
 *
389
 *
337
 * @return      If no timeout was specified, then a hash of the
-
 
338
 *          incoming call is returned. If a timeout is specified,
-
 
339
 *          then a hash of the incoming call is returned unless
-
 
340
 *          the timeout expires prior to receiving a message. In
-
 
341
 *          that case zero is returned.
-
 
342
 */
390
 */
343
ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs)
391
ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs)
344
{
392
{
345
    msg_t *msg;
-
 
346
    ipc_callid_t callid;
-
 
347
    connection_t *conn;
-
 
348
   
-
 
349
    assert(FIBRIL_connection);
393
    assert(FIBRIL_connection);
-
 
394
   
-
 
395
    /* Why doing this?
350
    /* GCC 4.1.0 coughs on FIBRIL_connection-> dereference,
396
     * GCC 4.1.0 coughs on FIBRIL_connection-> dereference.
351
     * GCC 4.1.1 happilly puts the rdhwr instruction in delay slot.
397
     * GCC 4.1.1 happilly puts the rdhwr instruction in delay slot.
352
     *           I would never expect to find so many errors in
398
     *           I would never expect to find so many errors in
353
     *           a compiler *($&$(*&$
399
     *           a compiler.
354
     */
400
     */
355
    conn = FIBRIL_connection;
401
    connection_t *conn = FIBRIL_connection;
356
 
402
   
357
    futex_down(&async_futex);
403
    futex_down(&async_futex);
358
 
404
   
359
    if (usecs) {
405
    if (usecs) {
360
        gettimeofday(&conn->wdata.expires, NULL);
406
        gettimeofday(&conn->wdata.expires, NULL);
361
        tv_add(&conn->wdata.expires, usecs);
407
        tv_add(&conn->wdata.expires, usecs);
362
    } else {
408
    } else
363
        conn->wdata.inlist = 0;
409
        conn->wdata.inlist = false;
364
    }
410
   
365
    /* If nothing in queue, wait until something arrives */
411
    /* If nothing in queue, wait until something arrives */
366
    while (list_empty(&conn->msg_queue)) {
412
    while (list_empty(&conn->msg_queue)) {
367
        if (usecs)
413
        if (usecs)
368
            insert_timeout(&conn->wdata);
414
            insert_timeout(&conn->wdata);
369
 
415
       
370
        conn->wdata.active = 0;
416
        conn->wdata.active = false;
-
 
417
       
371
        /*
418
        /*
372
         * Note: the current fibril will be rescheduled either due to a
419
         * Note: the current fibril will be rescheduled either due to a
373
         * timeout or due to an arriving message destined to it. In the
420
         * timeout or due to an arriving message destined to it. In the
374
         * former case, handle_expired_timeouts() and, in the latter
421
         * former case, handle_expired_timeouts() and, in the latter
375
         * case, route_call() will perform the wakeup.
422
         * case, route_call() will perform the wakeup.
376
         */
423
         */
377
        fibril_switch(FIBRIL_TO_MANAGER);
424
        fibril_switch(FIBRIL_TO_MANAGER);
-
 
425
       
378
        /*
426
        /*
379
         * Futex is up after getting back from async_manager get it
427
         * Futex is up after getting back from async_manager.
380
         * again.
428
         * Get it again.
381
         */
429
         */
382
        futex_down(&async_futex);
430
        futex_down(&async_futex);
383
        if (usecs && conn->wdata.timedout &&
431
        if ((usecs) && (conn->wdata.timedout)
384
            list_empty(&conn->msg_queue)) {
432
            && (list_empty(&conn->msg_queue))) {
385
            /* If we timed out -> exit */
433
            /* If we timed out -> exit */
386
            futex_up(&async_futex);
434
            futex_up(&async_futex);
387
            return 0;
435
            return 0;
388
        }
436
        }
389
    }
437
    }
390
   
438
   
391
    msg = list_get_instance(conn->msg_queue.next, msg_t, link);
439
    msg_t *msg = list_get_instance(conn->msg_queue.next, msg_t, link);
392
    list_remove(&msg->link);
440
    list_remove(&msg->link);
-
 
441
   
393
    callid = msg->callid;
442
    ipc_callid_t callid = msg->callid;
394
    *call = msg->call;
443
    *call = msg->call;
395
    free(msg);
444
    free(msg);
396
   
445
   
397
    futex_up(&async_futex);
446
    futex_up(&async_futex);
398
    return callid;
447
    return callid;
Line 400... Line 449...
400
 
449
 
401
/** Default fibril function that gets called to handle new connection.
450
/** Default fibril function that gets called to handle new connection.
402
 *
451
 *
403
 * This function is defined as a weak symbol - to be redefined in user code.
452
 * This function is defined as a weak symbol - to be redefined in user code.
404
 *
453
 *
405
 * @param callid    Hash of the incoming call.
454
 * @param callid Hash of the incoming call.
406
 * @param call      Data of the incoming call.
455
 * @param call   Data of the incoming call.
-
 
456
 *
407
 */
457
 */
408
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
458
static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
409
{
459
{
410
    ipc_answer_0(callid, ENOENT);
460
    ipc_answer_0(callid, ENOENT);
411
}
461
}
412
 
462
 
413
/** Default fibril function that gets called to handle interrupt notifications.
463
/** Default fibril function that gets called to handle interrupt notifications.
414
 *
464
 *
-
 
465
 * This function is defined as a weak symbol - to be redefined in user code.
-
 
466
 *
415
 * @param callid    Hash of the incoming call.
467
 * @param callid Hash of the incoming call.
416
 * @param call      Data of the incoming call.
468
 * @param call   Data of the incoming call.
-
 
469
 *
417
 */
470
 */
418
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
471
static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
419
{
472
{
420
}
473
}
421
 
474
 
422
/** Wrapper for client connection fibril.
475
/** Wrapper for client connection fibril.
423
 *
476
 *
424
 * When a new connection arrives, a fibril with this implementing function is
477
 * When a new connection arrives, a fibril with this implementing function is
425
 * created. It calls client_connection() and does the final cleanup.
478
 * created. It calls client_connection() and does the final cleanup.
426
 *
479
 *
427
 * @param arg       Connection structure pointer.
480
 * @param arg Connection structure pointer.
-
 
481
 *
-
 
482
 * @return Always zero.
428
 *
483
 *
429
 * @return      Always zero.
-
 
430
 */
484
 */
431
static int connection_fibril(void  *arg)
485
static int connection_fibril(void *arg)
432
{
486
{
433
    unsigned long key;
-
 
434
    msg_t *msg;
-
 
435
    int close_answered = 0;
-
 
436
 
487
    /*
437
    /* Setup fibril-local connection pointer */
488
     * Setup fibril-local connection pointer and call client_connection().
-
 
489
     *
-
 
490
     */
438
    FIBRIL_connection = (connection_t *) arg;
491
    FIBRIL_connection = (connection_t *) arg;
439
    FIBRIL_connection->cfibril(FIBRIL_connection->callid,
492
    FIBRIL_connection->cfibril(FIBRIL_connection->callid,
440
        &FIBRIL_connection->call);
493
        &FIBRIL_connection->call);
441
   
494
   
442
    /* Remove myself from the connection hash table */
495
    /* Remove myself from the connection hash table */
443
    futex_down(&async_futex);
496
    futex_down(&async_futex);
444
    key = FIBRIL_connection->in_phone_hash;
497
    unsigned long key = FIBRIL_connection->in_phone_hash;
445
    hash_table_remove(&conn_hash_table, &key, 1);
498
    hash_table_remove(&conn_hash_table, &key, 1);
446
    futex_up(&async_futex);
499
    futex_up(&async_futex);
447
   
500
   
448
    /* Answer all remaining messages with EHANGUP */
501
    /* Answer all remaining messages with EHANGUP */
449
    while (!list_empty(&FIBRIL_connection->msg_queue)) {
502
    while (!list_empty(&FIBRIL_connection->msg_queue)) {
-
 
503
        msg_t *msg
450
        msg = list_get_instance(FIBRIL_connection->msg_queue.next,
504
            = list_get_instance(FIBRIL_connection->msg_queue.next, msg_t, link);
451
            msg_t, link);
505
       
452
        list_remove(&msg->link);
506
        list_remove(&msg->link);
453
        if (msg->callid == FIBRIL_connection->close_callid)
-
 
454
            close_answered = 1;
-
 
455
        ipc_answer_0(msg->callid, EHANGUP);
507
        ipc_answer_0(msg->callid, EHANGUP);
456
        free(msg);
508
        free(msg);
457
    }
509
    }
-
 
510
   
458
    if (FIBRIL_connection->close_callid)
511
    if (FIBRIL_connection->close_callid)
459
        ipc_answer_0(FIBRIL_connection->close_callid, EOK);
512
        ipc_answer_0(FIBRIL_connection->close_callid, EOK);
460
   
513
   
461
    return 0;
514
    return 0;
462
}
515
}
463
 
516
 
464
/** Create a new fibril for a new connection.
517
/** Create a new fibril for a new connection.
465
 *
518
 *
466
 * Creates new fibril for connection, fills in connection structures and inserts
519
 * Create new fibril for connection, fill in connection structures and inserts
467
 * it into the hash table, so that later we can easily do routing of messages to
520
 * it into the hash table, so that later we can easily do routing of messages to
468
 * particular fibrils.
521
 * particular fibrils.
469
 *
522
 *
470
 * @param in_phone_hash Identification of the incoming connection.
523
 * @param in_phone_hash Identification of the incoming connection.
471
 * @param callid    Hash of the opening IPC_M_CONNECT_ME_TO call.
524
 * @param callid        Hash of the opening IPC_M_CONNECT_ME_TO call.
472
 *          If callid is zero, the connection was opened by
525
 *                      If callid is zero, the connection was opened by
473
 *          accepting the IPC_M_CONNECT_TO_ME call and this function
526
 *                      accepting the IPC_M_CONNECT_TO_ME call and this function
474
 *          is called directly by the server.
527
 *                      is called directly by the server.
475
 * @param call      Call data of the opening call.
528
 * @param call          Call data of the opening call.
476
 * @param cfibril   Fibril function that should be called upon opening the
529
 * @param cfibril       Fibril function that should be called upon opening the
477
 *          connection.
530
 *                      connection.
-
 
531
 *
-
 
532
 * @return New fibril id or NULL on failure.
478
 *
533
 *
479
 * @return      New fibril id or NULL on failure.
-
 
480
 */
534
 */
481
fid_t async_new_connection(ipcarg_t in_phone_hash, ipc_callid_t callid,
535
fid_t async_new_connection(ipcarg_t in_phone_hash, ipc_callid_t callid,
482
    ipc_call_t *call, void (*cfibril)(ipc_callid_t, ipc_call_t *))
536
    ipc_call_t *call, void (*cfibril)(ipc_callid_t, ipc_call_t *))
483
{
537
{
484
    connection_t *conn;
-
 
485
    unsigned long key;
-
 
486
 
-
 
487
    conn = malloc(sizeof(*conn));
538
    connection_t *conn = malloc(sizeof(*conn));
488
    if (!conn) {
539
    if (!conn) {
489
        if (callid)
540
        if (callid)
490
            ipc_answer_0(callid, ENOMEM);
541
            ipc_answer_0(callid, ENOMEM);
491
        return NULL;
542
        return NULL;
492
    }
543
    }
-
 
544
   
493
    conn->in_phone_hash = in_phone_hash;
545
    conn->in_phone_hash = in_phone_hash;
494
    list_initialize(&conn->msg_queue);
546
    list_initialize(&conn->msg_queue);
495
    conn->callid = callid;
547
    conn->callid = callid;
496
    conn->close_callid = 0;
548
    conn->close_callid = false;
-
 
549
   
497
    if (call)
550
    if (call)
498
        conn->call = *call;
551
        conn->call = *call;
-
 
552
   
499
    conn->wdata.active = 1; /* We will activate the fibril ASAP */
553
    /* We will activate the fibril ASAP */
-
 
554
    conn->wdata.active = true;
500
    conn->cfibril = cfibril;
555
    conn->cfibril = cfibril;
501
 
-
 
502
    conn->wdata.fid = fibril_create(connection_fibril, conn);
556
    conn->wdata.fid = fibril_create(connection_fibril, conn);
-
 
557
   
503
    if (!conn->wdata.fid) {
558
    if (!conn->wdata.fid) {
504
        free(conn);
559
        free(conn);
505
        if (callid)
560
        if (callid)
506
            ipc_answer_0(callid, ENOMEM);
561
            ipc_answer_0(callid, ENOMEM);
507
        return NULL;
562
        return NULL;
508
    }
563
    }
-
 
564
   
509
    /* Add connection to the connection hash table */
565
    /* Add connection to the connection hash table */
510
    key = conn->in_phone_hash;
566
    ipcarg_t key = conn->in_phone_hash;
-
 
567
   
511
    futex_down(&async_futex);
568
    futex_down(&async_futex);
512
    hash_table_insert(&conn_hash_table, &key, &conn->link);
569
    hash_table_insert(&conn_hash_table, &key, &conn->link);
513
    futex_up(&async_futex);
570
    futex_up(&async_futex);
514
 
571
   
515
    fibril_add_ready(conn->wdata.fid);
572
    fibril_add_ready(conn->wdata.fid);
516
 
573
   
517
    return conn->wdata.fid;
574
    return conn->wdata.fid;
518
}
575
}
519
 
576
 
520
/** Handle a call that was received.
577
/** Handle a call that was received.
521
 *
578
 *
522
 * If the call has the IPC_M_CONNECT_ME_TO method, a new connection is created.
579
 * If the call has the IPC_M_CONNECT_ME_TO method, a new connection is created.
523
 * Otherwise the call is routed to its connection fibril.
580
 * Otherwise the call is routed to its connection fibril.
524
 *
581
 *
525
 * @param callid    Hash of the incoming call.
582
 * @param callid Hash of the incoming call.
526
 * @param call      Data of the incoming call.
583
 * @param call   Data of the incoming call.
-
 
584
 *
527
 */
585
 */
528
static void handle_call(ipc_callid_t callid, ipc_call_t *call)
586
static void handle_call(ipc_callid_t callid, ipc_call_t *call)
529
{
587
{
530
    /* Unrouted call - do some default behaviour */
588
    /* Unrouted call - do some default behaviour */
531
    if ((callid & IPC_CALLID_NOTIFICATION)) {
589
    if ((callid & IPC_CALLID_NOTIFICATION)) {
532
        _in_interrupt_handler = 1;
-
 
533
        (*interrupt_received)(callid, call);
590
        process_notification(callid, call);
534
        _in_interrupt_handler = 0;
-
 
535
        return;
591
        return;
536
    }      
592
    }
537
 
593
   
538
    switch (IPC_GET_METHOD(*call)) {
594
    switch (IPC_GET_METHOD(*call)) {
539
    case IPC_M_CONNECT_ME_TO:
595
    case IPC_M_CONNECT_ME_TO:
540
        /* Open new connection with fibril etc. */
596
        /* Open new connection with fibril etc. */
541
        async_new_connection(IPC_GET_ARG5(*call), callid, call,
597
        async_new_connection(IPC_GET_ARG5(*call), callid, call,
542
            client_connection);
598
            client_connection);
543
        return;
599
        return;
544
    }
600
    }
545
 
601
   
546
    /* Try to route the call through the connection hash table */
602
    /* Try to route the call through the connection hash table */
547
    if (route_call(callid, call))
603
    if (route_call(callid, call))
548
        return;
604
        return;
549
 
605
   
550
    /* Unknown call from unknown phone - hang it up */
606
    /* Unknown call from unknown phone - hang it up */
551
    ipc_answer_0(callid, EHANGUP);
607
    ipc_answer_0(callid, EHANGUP);
552
}
608
}
553
 
609
 
554
/** Fire all timeouts that expired. */
610
/** Fire all timeouts that expired. */
555
static void handle_expired_timeouts(void)
611
static void handle_expired_timeouts(void)
556
{
612
{
557
    struct timeval tv;
613
    struct timeval tv;
558
    awaiter_t *waiter;
-
 
559
    link_t *cur;
-
 
560
 
-
 
561
    gettimeofday(&tv, NULL);
614
    gettimeofday(&tv, NULL);
-
 
615
   
562
    futex_down(&async_futex);
616
    futex_down(&async_futex);
563
 
617
   
564
    cur = timeout_list.next;
618
    link_t *cur = timeout_list.next;
565
    while (cur != &timeout_list) {
619
    while (cur != &timeout_list) {
566
        waiter = list_get_instance(cur, awaiter_t, link);
620
        awaiter_t *waiter = list_get_instance(cur, awaiter_t, link);
-
 
621
       
567
        if (tv_gt(&waiter->expires, &tv))
622
        if (tv_gt(&waiter->expires, &tv))
568
            break;
623
            break;
-
 
624
       
569
        cur = cur->next;
625
        cur = cur->next;
-
 
626
       
570
        list_remove(&waiter->link);
627
        list_remove(&waiter->link);
571
        waiter->inlist = 0;
628
        waiter->inlist = false;
572
        waiter->timedout = 1;
629
        waiter->timedout = true;
-
 
630
       
573
        /*
631
        /*
574
         * Redundant condition?
632
         * Redundant condition?
575
         * The fibril should not be active when it gets here.
633
         * The fibril should not be active when it gets here.
576
         */
634
         */
577
        if (!waiter->active) {
635
        if (!waiter->active) {
578
            waiter->active = 1;
636
            waiter->active = true;
579
            fibril_add_ready(waiter->fid);
637
            fibril_add_ready(waiter->fid);
580
        }
638
        }
581
    }
639
    }
582
 
640
   
583
    futex_up(&async_futex);
641
    futex_up(&async_futex);
584
}
642
}
585
 
643
 
586
/** Endless loop dispatching incoming calls and answers.
644
/** Endless loop dispatching incoming calls and answers.
587
 *
645
 *
588
 * @return      Never returns.
646
 * @return Never returns.
-
 
647
 *
589
 */
648
 */
590
static int async_manager_worker(void)
649
static int async_manager_worker(void)
591
{
650
{
592
    ipc_call_t call;
-
 
593
    ipc_callid_t callid;
-
 
594
    int timeout;
-
 
595
    awaiter_t *waiter;
-
 
596
    struct timeval tv;
-
 
597
 
-
 
598
    while (1) {
651
    while (true) {
599
        if (fibril_switch(FIBRIL_FROM_MANAGER)) {
652
        if (fibril_switch(FIBRIL_FROM_MANAGER)) {
600
            futex_up(&async_futex);
653
            futex_up(&async_futex);
601
            /*
654
            /*
602
             * async_futex is always held when entering a manager
655
             * async_futex is always held when entering a manager
603
             * fibril.
656
             * fibril.
604
             */
657
             */
605
            continue;
658
            continue;
606
        }
659
        }
-
 
660
       
607
        futex_down(&async_futex);
661
        futex_down(&async_futex);
-
 
662
       
-
 
663
        suseconds_t timeout;
608
        if (!list_empty(&timeout_list)) {
664
        if (!list_empty(&timeout_list)) {
-
 
665
            awaiter_t *waiter
609
            waiter = list_get_instance(timeout_list.next, awaiter_t,
666
                = list_get_instance(timeout_list.next, awaiter_t, link);
-
 
667
           
610
                link);
668
            struct timeval tv;
611
            gettimeofday(&tv, NULL);
669
            gettimeofday(&tv, NULL);
-
 
670
           
612
            if (tv_gteq(&tv, &waiter->expires)) {
671
            if (tv_gteq(&tv, &waiter->expires)) {
613
                futex_up(&async_futex);
672
                futex_up(&async_futex);
614
                handle_expired_timeouts();
673
                handle_expired_timeouts();
615
                continue;
674
                continue;
616
            } else
675
            } else
617
                timeout = tv_sub(&waiter->expires, &tv);
676
                timeout = tv_sub(&waiter->expires, &tv);
618
        } else
677
        } else
619
            timeout = SYNCH_NO_TIMEOUT;
678
            timeout = SYNCH_NO_TIMEOUT;
-
 
679
       
620
        futex_up(&async_futex);
680
        futex_up(&async_futex);
621
 
681
       
-
 
682
        ipc_call_t call;
-
 
683
        ipc_callid_t callid
622
        callid = ipc_wait_cycle(&call, timeout, SYNCH_FLAGS_NONE);
684
            = ipc_wait_cycle(&call, timeout, SYNCH_FLAGS_NONE);
623
 
685
       
624
        if (!callid) {
686
        if (!callid) {
625
            handle_expired_timeouts();
687
            handle_expired_timeouts();
626
            continue;
688
            continue;
627
        }
689
        }
628
 
690
       
629
        if (callid & IPC_CALLID_ANSWERED) {
691
        if (callid & IPC_CALLID_ANSWERED)
630
            continue;
692
            continue;
631
        }
693
       
632
 
-
 
633
        handle_call(callid, &call);
694
        handle_call(callid, &call);
634
    }
695
    }
635
   
696
   
636
    return 0;
697
    return 0;
637
}
698
}
638
 
699
 
639
/** Function to start async_manager as a standalone fibril.
700
/** Function to start async_manager as a standalone fibril.
640
 *
701
 *
641
 * When more kernel threads are used, one async manager should exist per thread.
702
 * When more kernel threads are used, one async manager should exist per thread.
642
 *
703
 *
643
 * @param arg       Unused.
704
 * @param arg Unused.
-
 
705
 * @return Never returns.
644
 *
706
 *
645
 * @return      Never returns.
-
 
646
 */
707
 */
647
static int async_manager_fibril(void *arg)
708
static int async_manager_fibril(void *arg)
648
{
709
{
649
    futex_up(&async_futex);
710
    futex_up(&async_futex);
-
 
711
   
650
    /*
712
    /*
651
     * async_futex is always locked when entering manager
713
     * async_futex is always locked when entering manager
652
     */
714
     */
653
    async_manager_worker();
715
    async_manager_worker();
654
   
716
   
Line 656... Line 718...
656
}
718
}
657
 
719
 
658
/** Add one manager to manager list. */
720
/** Add one manager to manager list. */
659
void async_create_manager(void)
721
void async_create_manager(void)
660
{
722
{
661
    fid_t fid;
-
 
662
 
-
 
663
    fid = fibril_create(async_manager_fibril, NULL);
723
    fid_t fid = fibril_create(async_manager_fibril, NULL);
664
    fibril_add_manager(fid);
724
    fibril_add_manager(fid);
665
}
725
}
666
 
726
 
667
/** Remove one manager from manager list */
727
/** Remove one manager from manager list */
668
void async_destroy_manager(void)
728
void async_destroy_manager(void)
Line 670... Line 730...
670
    fibril_remove_manager();
730
    fibril_remove_manager();
671
}
731
}
672
 
732
 
673
/** Initialize the async framework.
733
/** Initialize the async framework.
674
 *
734
 *
675
 * @return      Zero on success or an error code.
735
 * @return Zero on success or an error code.
676
 */
736
 */
677
int _async_init(void)
737
int _async_init(void)
678
{
738
{
679
    if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_CHAINS, 1,
739
    if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_CHAINS, 1,
680
        &conn_hash_table_ops)) {
740
        &conn_hash_table_ops)) {
Line 690... Line 750...
690
 * This function is called whenever a reply for an asynchronous message sent out
750
 * This function is called whenever a reply for an asynchronous message sent out
691
 * by the asynchronous framework is received.
751
 * by the asynchronous framework is received.
692
 *
752
 *
693
 * Notify the fibril which is waiting for this message that it has arrived.
753
 * Notify the fibril which is waiting for this message that it has arrived.
694
 *
754
 *
695
 * @param private   Pointer to the asynchronous message record.
755
 * @param arg    Pointer to the asynchronous message record.
696
 * @param retval    Value returned in the answer.
756
 * @param retval Value returned in the answer.
697
 * @param data      Call data of the answer.
757
 * @param data   Call data of the answer.
698
 */
758
 */
699
static void reply_received(void *private, int retval, ipc_call_t *data)
759
static void reply_received(void *arg, int retval, ipc_call_t *data)
700
{
760
{
701
    amsg_t *msg = (amsg_t *) private;
761
    amsg_t *msg = (amsg_t *) arg;
702
 
-
 
703
    msg->retval = retval;
762
    msg->retval = retval;
704
 
763
   
705
    futex_down(&async_futex);
764
    futex_down(&async_futex);
-
 
765
   
706
    /* Copy data after futex_down, just in case the call was detached */
766
    /* Copy data after futex_down, just in case the call was detached */
707
    if (msg->dataptr)
767
    if (msg->dataptr)
708
        *msg->dataptr = *data;
768
        *msg->dataptr = *data;
709
 
769
   
710
    write_barrier();
770
    write_barrier();
-
 
771
   
711
    /* Remove message from timeout list */
772
    /* Remove message from timeout list */
712
    if (msg->wdata.inlist)
773
    if (msg->wdata.inlist)
713
        list_remove(&msg->wdata.link);
774
        list_remove(&msg->wdata.link);
-
 
775
   
714
    msg->done = 1;
776
    msg->done = true;
715
    if (!msg->wdata.active) {
777
    if (!msg->wdata.active) {
716
        msg->wdata.active = 1;
778
        msg->wdata.active = true;
717
        fibril_add_ready(msg->wdata.fid);
779
        fibril_add_ready(msg->wdata.fid);
718
    }
780
    }
-
 
781
   
719
    futex_up(&async_futex);
782
    futex_up(&async_futex);
720
}
783
}
721
 
784
 
722
/** Send message and return id of the sent message.
785
/** Send message and return id of the sent message.
723
 *
786
 *
724
 * The return value can be used as input for async_wait() to wait for
787
 * The return value can be used as input for async_wait() to wait for
725
 * completion.
788
 * completion.
726
 *
789
 *
727
 * @param phoneid   Handle of the phone that will be used for the send.
790
 * @param phoneid Handle of the phone that will be used for the send.
728
 * @param method    Service-defined method.
791
 * @param method  Service-defined method.
729
 * @param arg1      Service-defined payload argument.
792
 * @param arg1    Service-defined payload argument.
730
 * @param arg2      Service-defined payload argument.
793
 * @param arg2    Service-defined payload argument.
731
 * @param arg3      Service-defined payload argument.
794
 * @param arg3    Service-defined payload argument.
732
 * @param arg4      Service-defined payload argument.
795
 * @param arg4    Service-defined payload argument.
733
 * @param dataptr   If non-NULL, storage where the reply data will be
796
 * @param dataptr If non-NULL, storage where the reply data will be
734
 *          stored.
797
 *                stored.
-
 
798
 *
-
 
799
 * @return Hash of the sent message or 0 on error.
735
 *
800
 *
736
 * @return      Hash of the sent message.
-
 
737
 */
801
 */
738
aid_t async_send_fast(int phoneid, ipcarg_t method, ipcarg_t arg1,
802
aid_t async_send_fast(int phoneid, ipcarg_t method, ipcarg_t arg1,
739
    ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipc_call_t *dataptr)
803
    ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipc_call_t *dataptr)
740
{
804
{
741
    amsg_t *msg;
805
    amsg_t *msg = malloc(sizeof(*msg));
742
 
806
   
743
    if (_in_interrupt_handler) {
-
 
744
        printf("Cannot send asynchronous request in interrupt "
-
 
745
            "handler.\n");
807
    if (!msg)
746
        _exit(1);
808
        return 0;
747
    }
809
   
748
 
-
 
749
    msg = malloc(sizeof(*msg));
-
 
750
    msg->done = 0;
810
    msg->done = false;
751
    msg->dataptr = dataptr;
811
    msg->dataptr = dataptr;
752
 
812
   
753
    /* We may sleep in the next method, but it will use its own mechanism */
813
    /* We may sleep in the next method, but it will use its own mechanism */
754
    msg->wdata.active = 1;
814
    msg->wdata.active = true;
755
               
815
   
756
    ipc_call_async_4(phoneid, method, arg1, arg2, arg3, arg4, msg,
816
    ipc_call_async_4(phoneid, method, arg1, arg2, arg3, arg4, msg,
757
        reply_received, 1);
817
        reply_received, true);
758
 
818
   
759
    return (aid_t) msg;
819
    return (aid_t) msg;
760
}
820
}
761
 
821
 
762
/** Send message and return id of the sent message
822
/** Send message and return id of the sent message
763
 *
823
 *
764
 * The return value can be used as input for async_wait() to wait for
824
 * The return value can be used as input for async_wait() to wait for
765
 * completion.
825
 * completion.
766
 *
826
 *
767
 * @param phoneid   Handle of the phone that will be used for the send.
827
 * @param phoneid Handle of the phone that will be used for the send.
768
 * @param method    Service-defined method.
828
 * @param method  Service-defined method.
769
 * @param arg1      Service-defined payload argument.
829
 * @param arg1    Service-defined payload argument.
770
 * @param arg2      Service-defined payload argument.
830
 * @param arg2    Service-defined payload argument.
771
 * @param arg3      Service-defined payload argument.
831
 * @param arg3    Service-defined payload argument.
772
 * @param arg4      Service-defined payload argument.
832
 * @param arg4    Service-defined payload argument.
773
 * @param arg5      Service-defined payload argument.
833
 * @param arg5    Service-defined payload argument.
774
 * @param dataptr   If non-NULL, storage where the reply data will be
834
 * @param dataptr If non-NULL, storage where the reply data will be
775
 *          stored.
835
 *                stored.
-
 
836
 *
-
 
837
 * @return Hash of the sent message or 0 on error.
776
 *
838
 *
777
 * @return      Hash of the sent message.
-
 
778
 */
839
 */
779
aid_t async_send_slow(int phoneid, ipcarg_t method, ipcarg_t arg1,
840
aid_t async_send_slow(int phoneid, ipcarg_t method, ipcarg_t arg1,
780
    ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t arg5,
841
    ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t arg5,
781
    ipc_call_t *dataptr)
842
    ipc_call_t *dataptr)
782
{
843
{
783
    amsg_t *msg;
844
    amsg_t *msg = malloc(sizeof(*msg));
784
 
845
   
785
    if (_in_interrupt_handler) {
-
 
786
        printf("Cannot send asynchronous request in interrupt "
-
 
787
            "handler.\n");
846
    if (!msg)
788
        _exit(1);
847
        return 0;
789
    }
848
   
790
 
-
 
791
    msg = malloc(sizeof(*msg));
-
 
792
    msg->done = 0;
849
    msg->done = false;
793
    msg->dataptr = dataptr;
850
    msg->dataptr = dataptr;
794
 
851
   
795
    /* We may sleep in next method, but it will use its own mechanism */
852
    /* We may sleep in next method, but it will use its own mechanism */
796
    msg->wdata.active = 1;
853
    msg->wdata.active = true;
797
 
854
   
798
    ipc_call_async_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, msg,
855
    ipc_call_async_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, msg,
799
        reply_received, 1);
856
        reply_received, true);
800
 
857
   
801
    return (aid_t) msg;
858
    return (aid_t) msg;
802
}
859
}
803
 
860
 
804
/** Wait for a message sent by the async framework.
861
/** Wait for a message sent by the async framework.
805
 *
862
 *
806
 * @param amsgid    Hash of the message to wait for.
863
 * @param amsgid Hash of the message to wait for.
807
 * @param retval    Pointer to storage where the retval of the answer will
864
 * @param retval Pointer to storage where the retval of the answer will
808
 *          be stored.
865
 *               be stored.
-
 
866
 *
809
 */
867
 */
810
void async_wait_for(aid_t amsgid, ipcarg_t *retval)
868
void async_wait_for(aid_t amsgid, ipcarg_t *retval)
811
{
869
{
812
    amsg_t *msg = (amsg_t *) amsgid;
870
    amsg_t *msg = (amsg_t *) amsgid;
813
 
871
   
814
    futex_down(&async_futex);
872
    futex_down(&async_futex);
815
    if (msg->done) {
873
    if (msg->done) {
816
        futex_up(&async_futex);
874
        futex_up(&async_futex);
817
        goto done;
875
        goto done;
818
    }
876
    }
819
 
877
   
820
    msg->wdata.fid = fibril_get_id();
878
    msg->wdata.fid = fibril_get_id();
821
    msg->wdata.active = 0;
879
    msg->wdata.active = false;
822
    msg->wdata.inlist = 0;
880
    msg->wdata.inlist = false;
-
 
881
   
823
    /* Leave the async_futex locked when entering this function */
882
    /* Leave the async_futex locked when entering this function */
824
    fibril_switch(FIBRIL_TO_MANAGER);
883
    fibril_switch(FIBRIL_TO_MANAGER);
-
 
884
   
825
    /* futex is up automatically after fibril_switch...*/
885
    /* Futex is up automatically after fibril_switch */
-
 
886
   
826
done:
887
done:
827
    if (retval)
888
    if (retval)
828
        *retval = msg->retval;
889
        *retval = msg->retval;
-
 
890
   
829
    free(msg);
891
    free(msg);
830
}
892
}
831
 
893
 
832
/** Wait for a message sent by the async framework, timeout variant.
894
/** Wait for a message sent by the async framework, timeout variant.
833
 *
895
 *
834
 * @param amsgid    Hash of the message to wait for.
896
 * @param amsgid  Hash of the message to wait for.
835
 * @param retval    Pointer to storage where the retval of the answer will
897
 * @param retval  Pointer to storage where the retval of the answer will
836
 *          be stored.
898
 *                be stored.
837
 * @param timeout   Timeout in microseconds.
899
 * @param timeout Timeout in microseconds.
-
 
900
 *
-
 
901
 * @return Zero on success, ETIMEOUT if the timeout has expired.
838
 *
902
 *
839
 * @return      Zero on success, ETIMEOUT if the timeout has expired.
-
 
840
 */
903
 */
841
int async_wait_timeout(aid_t amsgid, ipcarg_t *retval, suseconds_t timeout)
904
int async_wait_timeout(aid_t amsgid, ipcarg_t *retval, suseconds_t timeout)
842
{
905
{
843
    amsg_t *msg = (amsg_t *) amsgid;
906
    amsg_t *msg = (amsg_t *) amsgid;
844
 
907
   
845
    /* TODO: Let it go through the event read at least once */
908
    /* TODO: Let it go through the event read at least once */
846
    if (timeout < 0)
909
    if (timeout < 0)
847
        return ETIMEOUT;
910
        return ETIMEOUT;
848
 
911
   
849
    futex_down(&async_futex);
912
    futex_down(&async_futex);
850
    if (msg->done) {
913
    if (msg->done) {
851
        futex_up(&async_futex);
914
        futex_up(&async_futex);
852
        goto done;
915
        goto done;
853
    }
916
    }
854
 
917
   
855
    gettimeofday(&msg->wdata.expires, NULL);
918
    gettimeofday(&msg->wdata.expires, NULL);
856
    tv_add(&msg->wdata.expires, timeout);
919
    tv_add(&msg->wdata.expires, timeout);
857
 
920
   
858
    msg->wdata.fid = fibril_get_id();
921
    msg->wdata.fid = fibril_get_id();
859
    msg->wdata.active = 0;
922
    msg->wdata.active = false;
860
    insert_timeout(&msg->wdata);
923
    insert_timeout(&msg->wdata);
861
 
924
   
862
    /* Leave the async_futex locked when entering this function */
925
    /* Leave the async_futex locked when entering this function */
863
    fibril_switch(FIBRIL_TO_MANAGER);
926
    fibril_switch(FIBRIL_TO_MANAGER);
-
 
927
   
864
    /* futex is up automatically after fibril_switch...*/
928
    /* Futex is up automatically after fibril_switch */
865
 
929
   
866
    if (!msg->done)
930
    if (!msg->done)
867
        return ETIMEOUT;
931
        return ETIMEOUT;
868
 
932
   
869
done:
933
done:
870
    if (retval)
934
    if (retval)
871
        *retval = msg->retval;
935
        *retval = msg->retval;
-
 
936
   
872
    free(msg);
937
    free(msg);
873
 
938
   
874
    return 0;
939
    return 0;
875
}
940
}
876
 
941
 
877
/** Wait for specified time.
942
/** Wait for specified time.
878
 *
943
 *
879
 * The current fibril is suspended but the thread continues to execute.
944
 * The current fibril is suspended but the thread continues to execute.
880
 *
945
 *
881
 * @param timeout   Duration of the wait in microseconds.
946
 * @param timeout Duration of the wait in microseconds.
-
 
947
 *
882
 */
948
 */
883
void async_usleep(suseconds_t timeout)
949
void async_usleep(suseconds_t timeout)
884
{
950
{
885
    amsg_t *msg;
951
    amsg_t *msg = malloc(sizeof(*msg));
886
   
952
   
887
    if (_in_interrupt_handler) {
-
 
888
        printf("Cannot call async_usleep in interrupt handler.\n");
-
 
889
        _exit(1);
-
 
890
    }
-
 
891
 
-
 
892
    msg = malloc(sizeof(*msg));
-
 
893
    if (!msg)
953
    if (!msg)
894
        return;
954
        return;
895
 
955
   
896
    msg->wdata.fid = fibril_get_id();
956
    msg->wdata.fid = fibril_get_id();
897
    msg->wdata.active = 0;
957
    msg->wdata.active = false;
898
 
958
   
899
    gettimeofday(&msg->wdata.expires, NULL);
959
    gettimeofday(&msg->wdata.expires, NULL);
900
    tv_add(&msg->wdata.expires, timeout);
960
    tv_add(&msg->wdata.expires, timeout);
901
 
961
   
902
    futex_down(&async_futex);
962
    futex_down(&async_futex);
-
 
963
   
903
    insert_timeout(&msg->wdata);
964
    insert_timeout(&msg->wdata);
-
 
965
   
904
    /* Leave the async_futex locked when entering this function */
966
    /* Leave the async_futex locked when entering this function */
905
    fibril_switch(FIBRIL_TO_MANAGER);
967
    fibril_switch(FIBRIL_TO_MANAGER);
-
 
968
   
906
    /* futex is up automatically after fibril_switch()...*/
969
    /* Futex is up automatically after fibril_switch() */
-
 
970
   
907
    free(msg);
971
    free(msg);
908
}
972
}
909
 
973
 
910
/** Setter for client_connection function pointer.
974
/** Setter for client_connection function pointer.
911
 *
975
 *
912
 * @param conn      Function that will implement a new connection fibril.
976
 * @param conn Function that will implement a new connection fibril.
-
 
977
 *
913
 */
978
 */
914
void async_set_client_connection(async_client_conn_t conn)
979
void async_set_client_connection(async_client_conn_t conn)
915
{
980
{
916
    client_connection = conn;
981
    client_connection = conn;
917
}
982
}
918
 
983
 
919
/** Setter for interrupt_received function pointer.
984
/** Setter for interrupt_received function pointer.
920
 *
985
 *
921
 * @param conn      Function that will implement a new interrupt
986
 * @param intr Function that will implement a new interrupt
922
 *          notification fibril.
987
 *             notification fibril.
923
 */
988
 */
924
void async_set_interrupt_received(async_client_conn_t conn)
989
void async_set_interrupt_received(async_client_conn_t intr)
925
{
990
{
926
    interrupt_received = conn;
991
    interrupt_received = intr;
927
}
992
}
928
 
993
 
929
/** Pseudo-synchronous message sending - fast version.
994
/** Pseudo-synchronous message sending - fast version.
930
 *
995
 *
931
 * Send message asynchronously and return only after the reply arrives.
996
 * Send message asynchronously and return only after the reply arrives.
932
 *
997
 *
933
 * This function can only transfer 4 register payload arguments. For
998
 * This function can only transfer 4 register payload arguments. For
934
 * transferring more arguments, see the slower async_req_slow().
999
 * transferring more arguments, see the slower async_req_slow().
935
 *
1000
 *
936
 * @param phoneid   Hash of the phone through which to make the call.
1001
 * @param phoneid Hash of the phone through which to make the call.
937
 * @param method    Method of the call.
1002
 * @param method  Method of the call.
938
 * @param arg1      Service-defined payload argument.
1003
 * @param arg1    Service-defined payload argument.
939
 * @param arg2      Service-defined payload argument.
1004
 * @param arg2    Service-defined payload argument.
940
 * @param arg3      Service-defined payload argument.
1005
 * @param arg3    Service-defined payload argument.
941
 * @param arg4      Service-defined payload argument.
1006
 * @param arg4    Service-defined payload argument.
942
 * @param r1        If non-NULL, storage for the 1st reply argument.
1007
 * @param r1      If non-NULL, storage for the 1st reply argument.
943
 * @param r2        If non-NULL, storage for the 2nd reply argument.
1008
 * @param r2      If non-NULL, storage for the 2nd reply argument.
944
 * @param r3        If non-NULL, storage for the 3rd reply argument.
1009
 * @param r3      If non-NULL, storage for the 3rd reply argument.
945
 * @param r4        If non-NULL, storage for the 4th reply argument.
1010
 * @param r4      If non-NULL, storage for the 4th reply argument.
946
 * @param r5        If non-NULL, storage for the 5th reply argument.
1011
 * @param r5      If non-NULL, storage for the 5th reply argument.
-
 
1012
 *
947
 * @return      Return code of the reply or a negative error code.
1013
 * @return Return code of the reply or a negative error code.
-
 
1014
 *
948
 */
1015
 */
949
ipcarg_t async_req_fast(int phoneid, ipcarg_t method, ipcarg_t arg1,
1016
ipcarg_t async_req_fast(int phoneid, ipcarg_t method, ipcarg_t arg1,
950
    ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t *r1, ipcarg_t *r2,
1017
    ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t *r1, ipcarg_t *r2,
951
    ipcarg_t *r3, ipcarg_t *r4, ipcarg_t *r5)
1018
    ipcarg_t *r3, ipcarg_t *r4, ipcarg_t *r5)
952
{
1019
{
953
    ipc_call_t result;
1020
    ipc_call_t result;
954
    ipcarg_t rc;
-
 
955
 
-
 
956
    aid_t eid = async_send_4(phoneid, method, arg1, arg2, arg3, arg4,
1021
    aid_t eid = async_send_4(phoneid, method, arg1, arg2, arg3, arg4,
957
        &result);
1022
        &result);
-
 
1023
   
-
 
1024
    ipcarg_t rc;
958
    async_wait_for(eid, &rc);
1025
    async_wait_for(eid, &rc);
-
 
1026
   
959
    if (r1)
1027
    if (r1)
960
        *r1 = IPC_GET_ARG1(result);
1028
        *r1 = IPC_GET_ARG1(result);
-
 
1029
   
961
    if (r2)
1030
    if (r2)
962
        *r2 = IPC_GET_ARG2(result);
1031
        *r2 = IPC_GET_ARG2(result);
-
 
1032
   
963
    if (r3)
1033
    if (r3)
964
        *r3 = IPC_GET_ARG3(result);
1034
        *r3 = IPC_GET_ARG3(result);
-
 
1035
   
965
    if (r4)
1036
    if (r4)
966
        *r4 = IPC_GET_ARG4(result);
1037
        *r4 = IPC_GET_ARG4(result);
-
 
1038
   
967
    if (r5)
1039
    if (r5)
968
        *r5 = IPC_GET_ARG5(result);
1040
        *r5 = IPC_GET_ARG5(result);
-
 
1041
   
969
    return rc;
1042
    return rc;
970
}
1043
}
971
 
1044
 
972
/** Pseudo-synchronous message sending - slow version.
1045
/** Pseudo-synchronous message sending - slow version.
973
 *
1046
 *
974
 * Send message asynchronously and return only after the reply arrives.
1047
 * Send message asynchronously and return only after the reply arrives.
975
 *
1048
 *
976
 * @param phoneid   Hash of the phone through which to make the call.
1049
 * @param phoneid Hash of the phone through which to make the call.
977
 * @param method    Method of the call.
1050
 * @param method  Method of the call.
978
 * @param arg1      Service-defined payload argument.
1051
 * @param arg1    Service-defined payload argument.
979
 * @param arg2      Service-defined payload argument.
1052
 * @param arg2    Service-defined payload argument.
980
 * @param arg3      Service-defined payload argument.
1053
 * @param arg3    Service-defined payload argument.
981
 * @param arg4      Service-defined payload argument.
1054
 * @param arg4    Service-defined payload argument.
982
 * @param arg5      Service-defined payload argument.
1055
 * @param arg5    Service-defined payload argument.
983
 * @param r1        If non-NULL, storage for the 1st reply argument.
1056
 * @param r1      If non-NULL, storage for the 1st reply argument.
984
 * @param r2        If non-NULL, storage for the 2nd reply argument.
1057
 * @param r2      If non-NULL, storage for the 2nd reply argument.
985
 * @param r3        If non-NULL, storage for the 3rd reply argument.
1058
 * @param r3      If non-NULL, storage for the 3rd reply argument.
986
 * @param r4        If non-NULL, storage for the 4th reply argument.
1059
 * @param r4      If non-NULL, storage for the 4th reply argument.
987
 * @param r5        If non-NULL, storage for the 5th reply argument.
1060
 * @param r5      If non-NULL, storage for the 5th reply argument.
-
 
1061
 *
988
 * @return      Return code of the reply or a negative error code.
1062
 * @return Return code of the reply or a negative error code.
-
 
1063
 *
989
 */
1064
 */
990
ipcarg_t async_req_slow(int phoneid, ipcarg_t method, ipcarg_t arg1,
1065
ipcarg_t async_req_slow(int phoneid, ipcarg_t method, ipcarg_t arg1,
991
    ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t arg5, ipcarg_t *r1,
1066
    ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipcarg_t arg5, ipcarg_t *r1,
992
    ipcarg_t *r2, ipcarg_t *r3, ipcarg_t *r4, ipcarg_t *r5)
1067
    ipcarg_t *r2, ipcarg_t *r3, ipcarg_t *r4, ipcarg_t *r5)
993
{
1068
{
994
    ipc_call_t result;
1069
    ipc_call_t result;
995
    ipcarg_t rc;
-
 
996
 
-
 
997
    aid_t eid = async_send_5(phoneid, method, arg1, arg2, arg3, arg4, arg5,
1070
    aid_t eid = async_send_5(phoneid, method, arg1, arg2, arg3, arg4, arg5,
998
        &result);
1071
        &result);
-
 
1072
   
-
 
1073
    ipcarg_t rc;
999
    async_wait_for(eid, &rc);
1074
    async_wait_for(eid, &rc);
-
 
1075
   
1000
    if (r1)
1076
    if (r1)
1001
        *r1 = IPC_GET_ARG1(result);
1077
        *r1 = IPC_GET_ARG1(result);
-
 
1078
   
1002
    if (r2)
1079
    if (r2)
1003
        *r2 = IPC_GET_ARG2(result);
1080
        *r2 = IPC_GET_ARG2(result);
-
 
1081
   
1004
    if (r3)
1082
    if (r3)
1005
        *r3 = IPC_GET_ARG3(result);
1083
        *r3 = IPC_GET_ARG3(result);
-
 
1084
   
1006
    if (r4)
1085
    if (r4)
1007
        *r4 = IPC_GET_ARG4(result);
1086
        *r4 = IPC_GET_ARG4(result);
-
 
1087
   
1008
    if (r5)
1088
    if (r5)
1009
        *r5 = IPC_GET_ARG5(result);
1089
        *r5 = IPC_GET_ARG5(result);
-
 
1090
   
1010
    return rc;
1091
    return rc;
1011
}
1092
}
1012
 
1093
 
1013
/** @}
1094
/** @}
1014
 */
1095
 */