Subversion Repositories HelenOS-historic

Rev

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

Rev 1502 Rev 1568
Line 109... Line 109...
109
void ipc_phone_connect(phone_t *phone, answerbox_t *box)
109
void ipc_phone_connect(phone_t *phone, answerbox_t *box)
110
{
110
{
111
    spinlock_lock(&phone->lock);
111
    spinlock_lock(&phone->lock);
112
 
112
 
113
    ASSERT(!phone->callee);
113
    ASSERT(!phone->callee);
114
    phone->busy = IPC_BUSY_CONNECTED;
114
    phone->state = IPC_PHONE_CONNECTED;
115
    phone->callee = box;
115
    phone->callee = box;
116
 
116
 
117
    spinlock_lock(&box->lock);
117
    spinlock_lock(&box->lock);
118
    list_append(&phone->list, &box->connected_phones);
118
    list_append(&phone->list, &box->connected_phones);
119
    spinlock_unlock(&box->lock);
119
    spinlock_unlock(&box->lock);
Line 125... Line 125...
125
 */
125
 */
126
void ipc_phone_init(phone_t *phone)
126
void ipc_phone_init(phone_t *phone)
127
{
127
{
128
    spinlock_initialize(&phone->lock, "phone_lock");
128
    spinlock_initialize(&phone->lock, "phone_lock");
129
    phone->callee = NULL;
129
    phone->callee = NULL;
130
    phone->busy = IPC_BUSY_FREE;
130
    phone->state = IPC_PHONE_FREE;
131
    atomic_set(&phone->active_calls, 0);
131
    atomic_set(&phone->active_calls, 0);
132
}
132
}
133
 
133
 
134
/** Helper function to facilitate synchronous calls */
134
/** Helper function to facilitate synchronous calls */
135
void ipc_call_sync(phone_t *phone, call_t *request)
135
void ipc_call_sync(phone_t *phone, call_t *request)
Line 182... Line 182...
182
 */
182
 */
183
void ipc_backsend_err(phone_t *phone, call_t *call, __native err)
183
void ipc_backsend_err(phone_t *phone, call_t *call, __native err)
184
{
184
{
185
    call->data.phone = phone;
185
    call->data.phone = phone;
186
    atomic_inc(&phone->active_calls);
186
    atomic_inc(&phone->active_calls);
187
    if (phone->busy == IPC_BUSY_CONNECTED)
-
 
188
        IPC_SET_RETVAL(call->data, EHANGUP);
-
 
189
    else
-
 
190
        IPC_SET_RETVAL(call->data, ENOENT);
187
    IPC_SET_RETVAL(call->data, err);
191
 
-
 
192
    _ipc_answer_free_call(call);
188
    _ipc_answer_free_call(call);
193
}
189
}
194
 
190
 
195
/* Unsafe unchecking ipc_call */
191
/* Unsafe unchecking ipc_call */
196
static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
192
static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
Line 214... Line 210...
214
int ipc_call(phone_t *phone, call_t *call)
210
int ipc_call(phone_t *phone, call_t *call)
215
{
211
{
216
    answerbox_t *box;
212
    answerbox_t *box;
217
 
213
 
218
    spinlock_lock(&phone->lock);
214
    spinlock_lock(&phone->lock);
219
 
-
 
220
    box = phone->callee;
-
 
221
    if (!box) {
-
 
222
        /* Trying to send over disconnected phone */
215
    if (phone->state != IPC_PHONE_CONNECTED) {
223
        spinlock_unlock(&phone->lock);
216
        spinlock_unlock(&phone->lock);
224
        if (call->flags & IPC_CALL_FORWARDED) {
217
        if (call->flags & IPC_CALL_FORWARDED) {
225
            IPC_SET_RETVAL(call->data, EFORWARD);
218
            IPC_SET_RETVAL(call->data, EFORWARD);
226
            _ipc_answer_free_call(call);
219
            _ipc_answer_free_call(call);
227
        } else { /* Simulate sending back a message */
220
        } else {
228
            if (phone->busy == IPC_BUSY_CONNECTED)
221
            if (phone->state == IPC_PHONE_HUNGUP)
229
                ipc_backsend_err(phone, call, EHANGUP);
222
                ipc_backsend_err(phone, call, EHANGUP);
230
            else
223
            else
231
                ipc_backsend_err(phone, call, ENOENT);
224
                ipc_backsend_err(phone, call, ENOENT);
232
        }
225
        }
233
 
-
 
234
        return ENOENT;
226
        return ENOENT;
235
    }
227
    }
-
 
228
    box = phone->callee;
236
    _ipc_call(phone, box, call);
229
    _ipc_call(phone, box, call);
237
   
230
   
238
    spinlock_unlock(&phone->lock);
231
    spinlock_unlock(&phone->lock);
239
    return 0;
232
    return 0;
240
}
233
}
241
 
234
 
242
/** Disconnect phone from answerbox
235
/** Disconnect phone from answerbox
243
 *
236
 *
244
 * It is allowed to call disconnect on already disconnected phone
237
 * This call leaves the phone in HUNGUP state. The change to 'free' is done
-
 
238
 * lazily later.
245
 *
239
 *
-
 
240
 * @param phone Phone to be hung up
-
 
241
 * @param aggressive If false, the phone is only marked hungup, and all
-
 
242
 *              messages are allowed to complete.
-
 
243
 *              If true, all messages in all queues are discarded. There
-
 
244
 *              may still be some messages that will be 'in-transit' on
-
 
245
 *              other CPU.
-
 
246
 *              
246
 * @return 0 - phone disconnected, -1 - the phone was already disconnected
247
 * @return 0 - phone disconnected, -1 - the phone was already disconnected
247
 */
248
 */
248
int ipc_phone_hangup(phone_t *phone)
249
int ipc_phone_hangup(phone_t *phone, int aggressive)
249
{
250
{
250
    answerbox_t *box;
251
    answerbox_t *box;
251
    call_t *call;
252
    call_t *call;
252
   
253
   
253
    spinlock_lock(&phone->lock);
254
    spinlock_lock(&phone->lock);
254
    box = phone->callee;
-
 
255
    if (!box) {
-
 
256
        if (phone->busy == IPC_BUSY_CONNECTING) {
255
    if (phone->state == IPC_PHONE_FREE || phone->state ==IPC_PHONE_HUNGUP \
257
            spinlock_unlock(&phone->lock);
-
 
258
            return -1;
-
 
259
        }
-
 
260
        /* Already disconnected phone */
-
 
261
        phone->busy = IPC_BUSY_FREE;
256
        || phone->state == IPC_PHONE_CONNECTING) {
262
        spinlock_unlock(&phone->lock);
257
        spinlock_unlock(&phone->lock);
263
        return 0;
258
        return -1;
264
    }
259
    }
-
 
260
    box = phone->callee;
-
 
261
    if (phone->state != IPC_PHONE_SLAMMED) {
-
 
262
        /* Remove myself from answerbox */
-
 
263
        spinlock_lock(&box->lock);
-
 
264
        list_remove(&phone->list);
-
 
265
        spinlock_unlock(&box->lock);
265
 
266
 
266
    spinlock_lock(&box->lock);
-
 
267
    list_remove(&phone->list);
-
 
268
    phone->callee = NULL;
267
        if (phone->state != IPC_PHONE_SLAMMED) {
269
    spinlock_unlock(&box->lock);
-
 
270
 
-
 
271
    call = ipc_call_alloc(0);
268
            call = ipc_call_alloc(0);
272
    IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
269
            IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
273
    call->flags |= IPC_CALL_DISCARD_ANSWER;
270
            call->flags |= IPC_CALL_DISCARD_ANSWER;
274
    _ipc_call(phone, box, call);
271
            _ipc_call(phone, box, call);
-
 
272
        }
-
 
273
    }
275
 
274
 
-
 
275
    if (aggressive && atomic_get(&phone->active_calls) > 0) {
276
    phone->busy = IPC_BUSY_FREE;
276
        /* TODO: Do some stuff be VERY aggressive */
-
 
277
    }
277
 
278
 
-
 
279
    phone->callee = 0;
-
 
280
   
-
 
281
    phone->state = IPC_PHONE_HUNGUP;
278
    spinlock_unlock(&phone->lock);
282
    spinlock_unlock(&phone->lock);
279
 
283
 
280
    return 0;
284
    return 0;
281
}
285
}
282
 
286
 
Line 378... Line 382...
378
    call_t *call;
382
    call_t *call;
379
    phone_t *phone;
383
    phone_t *phone;
380
   
384
   
381
    /* Disconnect all our phones ('ipc_phone_hangup') */
385
    /* Disconnect all our phones ('ipc_phone_hangup') */
382
    for (i=0;i < IPC_MAX_PHONES; i++)
386
    for (i=0;i < IPC_MAX_PHONES; i++)
383
        ipc_phone_hangup(&task->phones[i]);
387
        ipc_phone_hangup(&task->phones[i], 1);
384
 
388
 
385
    /* Disconnect all connected irqs */
389
    /* Disconnect all connected irqs */
386
    ipc_irq_cleanup(&task->answerbox);
390
    ipc_irq_cleanup(&task->answerbox);
387
 
391
 
388
    /* Disconnect all phones connected to our answerbox */
392
    /* Disconnect all phones connected to our answerbox */
Line 396... Line 400...
396
            spinlock_unlock(&task->answerbox.lock);
400
            spinlock_unlock(&task->answerbox.lock);
397
            goto restart_phones;
401
            goto restart_phones;
398
        }
402
        }
399
       
403
       
400
        /* Disconnect phone */
404
        /* Disconnect phone */
-
 
405
        ASSERT(phone->state == IPC_PHONE_CONNECTED);
401
        phone->callee = NULL;
406
        phone->state = IPC_PHONE_SLAMMED;
402
        list_remove(&phone->list);
407
        list_remove(&phone->list);
403
 
408
 
404
        spinlock_unlock(&phone->lock);
409
        spinlock_unlock(&phone->lock);
405
    }
410
    }
406
 
411
 
Line 409... Line 414...
409
    ipc_cleanup_call_list(&task->answerbox.dispatched_calls);
414
    ipc_cleanup_call_list(&task->answerbox.dispatched_calls);
410
    ipc_cleanup_call_list(&task->answerbox.calls);
415
    ipc_cleanup_call_list(&task->answerbox.calls);
411
    spinlock_unlock(&task->answerbox.lock);
416
    spinlock_unlock(&task->answerbox.lock);
412
   
417
   
413
    /* Wait for all async answers to arrive */
418
    /* Wait for all async answers to arrive */
-
 
419
    while (1) {
-
 
420
        /* Go through all phones, until all are FREE... */
-
 
421
        /* Locking not needed, no one else should modify
-
 
422
         * it, when we are in cleanup */
-
 
423
        for (i=0;i < IPC_MAX_PHONES; i++) {
-
 
424
            if (task->phones[i].state == IPC_PHONE_HUNGUP && \
414
    while (atomic_get(&task->active_calls)) {
425
                atomic_get(&task->phones[i].active_calls) == 0)
-
 
426
                task->phones[i].state = IPC_PHONE_FREE;
-
 
427
            if (task->phones[i].state != IPC_PHONE_FREE)
-
 
428
                break;
-
 
429
        }
-
 
430
        /* Voila, got into cleanup */
-
 
431
        if (i == IPC_MAX_PHONES)
-
 
432
            break;
-
 
433
       
415
        call = ipc_wait_for_call(&task->answerbox, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
434
        call = ipc_wait_for_call(&task->answerbox, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
416
        ASSERT((call->flags & IPC_CALL_ANSWERED) || (call->flags & IPC_CALL_NOTIF));
435
        ASSERT((call->flags & IPC_CALL_ANSWERED) || (call->flags & IPC_CALL_NOTIF));
417
        ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
436
        ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
418
       
437
       
419
        atomic_dec(&task->active_calls);
438
        atomic_dec(&task->active_calls);