Subversion Repositories HelenOS-historic

Rev

Rev 1443 | Rev 1489 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1443 Rev 1463
Line 33... Line 33...
33
#include <libadt/list.h>
33
#include <libadt/list.h>
34
#include <stdio.h>
34
#include <stdio.h>
35
#include <unistd.h>
35
#include <unistd.h>
36
#include <futex.h>
36
#include <futex.h>
37
#include <kernel/synch/synch.h>
37
#include <kernel/synch/synch.h>
-
 
38
#include <async.h>
-
 
39
#include <psthread.h>
38
 
40
 
39
/** Structure used for keeping track of sent async msgs
41
/** Structure used for keeping track of sent async msgs
40
 * and queing unsent msgs
42
 * and queing unsent msgs
41
 *
43
 *
42
 */
44
 */
Line 50... Line 52...
50
        struct {
52
        struct {
51
            ipc_call_t data;
53
            ipc_call_t data;
52
            int phoneid;
54
            int phoneid;
53
        } msg;
55
        } msg;
54
    }u;
56
    }u;
-
 
57
    pstid_t ptid;   /**< Thread waiting for sending this msg */
55
} async_call_t;
58
} async_call_t;
56
 
59
 
57
LIST_INITIALIZE(dispatched_calls);
60
LIST_INITIALIZE(dispatched_calls);
-
 
61
 
-
 
62
/* queued_calls is protcted by async_futex, because if the
-
 
63
 * call cannot be sent into kernel, async framework is used
-
 
64
 * automatically
-
 
65
 */
58
LIST_INITIALIZE(queued_calls);
66
LIST_INITIALIZE(queued_calls); /**< List of async calls that were not accepted
-
 
67
                *   by kernel */
59
 
68
 
60
static atomic_t ipc_futex = FUTEX_INITIALIZER;
69
static atomic_t ipc_futex = FUTEX_INITIALIZER;
61
 
70
 
62
int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1,
71
int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1,
63
          ipcarg_t *result)
72
          ipcarg_t *result)
Line 123... Line 132...
123
        if (callback)
132
        if (callback)
124
            callback(private, ENOMEM, NULL);
133
            callback(private, ENOMEM, NULL);
125
        return;
134
        return;
126
    }
135
    }
127
       
136
 
-
 
137
    call->callback = callback;
-
 
138
    call->private = private;
-
 
139
 
-
 
140
    /* We need to make sure that we get callid before
-
 
141
     * another thread accesses the queue again */
-
 
142
    futex_down(&ipc_futex);
128
    callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1, arg2);
143
    callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1, arg2);
129
    if (callid == IPC_CALLRET_FATAL) {
144
    if (callid == IPC_CALLRET_FATAL) {
-
 
145
        futex_up(&ipc_futex);
130
        /* Call asynchronous handler with error code */
146
        /* Call asynchronous handler with error code */
131
        if (callback)
147
        if (callback)
132
            callback(private, ENOENT, NULL);
148
            callback(private, ENOENT, NULL);
133
        free(call);
149
        free(call);
134
        return;
150
        return;
135
    }
151
    }
136
 
152
 
137
    call->callback = callback;
-
 
138
    call->private = private;
-
 
139
 
-
 
140
    if (callid == IPC_CALLRET_TEMPORARY) {
153
    if (callid == IPC_CALLRET_TEMPORARY) {
141
        /* Add asynchronous call to queue of non-dispatched async calls */
154
        futex_up(&ipc_futex);
-
 
155
 
142
        call->u.msg.phoneid = phoneid;
156
        call->u.msg.phoneid = phoneid;
143
        IPC_SET_METHOD(call->u.msg.data, method);
157
        IPC_SET_METHOD(call->u.msg.data, method);
144
        IPC_SET_ARG1(call->u.msg.data, arg1);
158
        IPC_SET_ARG1(call->u.msg.data, arg1);
145
        IPC_SET_ARG2(call->u.msg.data, arg2);
159
        IPC_SET_ARG2(call->u.msg.data, arg2);
146
       
160
 
-
 
161
        call->ptid = psthread_get_id();
147
        futex_down(&ipc_futex);
162
        futex_down(&async_futex);
148
        list_append(&call->list, &queued_calls);
163
        list_append(&call->list, &queued_calls);
-
 
164
 
149
        futex_up(&ipc_futex);
165
        psthread_schedule_next_adv(PS_TO_MANAGER);
-
 
166
        /* Async futex unlocked by previous call */
150
        return;
167
        return;
151
    }
168
    }
152
    call->u.callid = callid;
169
    call->u.callid = callid;
153
    /* Add call to list of dispatched calls */
170
    /* Add call to list of dispatched calls */
154
    futex_down(&ipc_futex);
-
 
155
    list_append(&call->list, &dispatched_calls);
171
    list_append(&call->list, &dispatched_calls);
156
    futex_up(&ipc_futex);
172
    futex_up(&ipc_futex);
157
}
173
}
158
 
174
 
159
 
175
 
Line 192... Line 208...
192
static void try_dispatch_queued_calls(void)
208
static void try_dispatch_queued_calls(void)
193
{
209
{
194
    async_call_t *call;
210
    async_call_t *call;
195
    ipc_callid_t callid;
211
    ipc_callid_t callid;
196
 
212
 
-
 
213
    /* TODO: integrate intelligently ipc_futex, so that it
-
 
214
     * is locked during ipc_call_async, until it is added
-
 
215
     * to dispatched_calls
-
 
216
     */
197
    futex_down(&ipc_futex);
217
    futex_down(&async_futex);
198
    while (!list_empty(&queued_calls)) {
218
    while (!list_empty(&queued_calls)) {
199
        call = list_get_instance(queued_calls.next, async_call_t,
219
        call = list_get_instance(queued_calls.next, async_call_t,
200
                     list);
220
                     list);
201
 
221
 
202
        callid = _ipc_call_async(call->u.msg.phoneid,
222
        callid = _ipc_call_async(call->u.msg.phoneid,
203
                     &call->u.msg.data);
223
                     &call->u.msg.data);
204
        if (callid == IPC_CALLRET_TEMPORARY)
224
        if (callid == IPC_CALLRET_TEMPORARY) {
205
            break;
225
            break;
-
 
226
        }
206
        list_remove(&call->list);
227
        list_remove(&call->list);
207
 
228
 
-
 
229
        futex_up(&async_futex);
-
 
230
        psthread_add_ready(call->ptid);
-
 
231
       
208
        if (callid == IPC_CALLRET_FATAL) {
232
        if (callid == IPC_CALLRET_FATAL) {
209
            futex_up(&ipc_futex);
-
 
210
            if (call->callback)
233
            if (call->callback)
211
                call->callback(call->private, ENOENT, NULL);
234
                call->callback(call->private, ENOENT, NULL);
212
            free(call);
235
            free(call);
213
            futex_down(&ipc_futex);
-
 
214
        } else {
236
        } else {
215
            call->u.callid = callid;
237
            call->u.callid = callid;
-
 
238
            futex_down(&ipc_futex);
216
            list_append(&call->list, &dispatched_calls);
239
            list_append(&call->list, &dispatched_calls);
-
 
240
            futex_up(&ipc_futex);
217
        }
241
        }
-
 
242
        futex_down(&async_futex);
218
    }
243
    }
219
    futex_up(&ipc_futex);
244
    futex_up(&async_futex);
220
}
245
}
221
 
246
 
222
/** Handle received answer
247
/** Handle received answer
223
 *
248
 *
224
 * TODO: Make it use hash table
249
 * TODO: Make it use hash table
Line 262... Line 287...
262
 */
287
 */
263
ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags)
288
ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags)
264
{
289
{
265
    ipc_callid_t callid;
290
    ipc_callid_t callid;
266
 
291
 
267
    try_dispatch_queued_calls();
-
 
268
   
-
 
269
    callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
292
    callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
270
    /* Handle received answers */
293
    /* Handle received answers */
271
    if (callid & IPC_CALLID_ANSWERED)
294
    if (callid & IPC_CALLID_ANSWERED) {
272
        handle_answer(callid, call);
295
        handle_answer(callid, call);
-
 
296
        try_dispatch_queued_calls();
-
 
297
    }
273
 
298
 
274
    return callid;
299
    return callid;
275
}
300
}
276
 
301
 
277
/** Wait some time for an IPC call.
302
/** Wait some time for an IPC call.