Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/fibril_synch.c

    r45cbcaf4 r2654afb  
    105105        fibril_t *f = (fibril_t *) fibril_get_id();
    106106
    107         if (fibril_get_sercount() != 0)
    108                 abort();
    109 
    110107        futex_down(&async_futex);
    111108        if (fm->counter-- <= 0) {
     
    197194        fibril_t *f = (fibril_t *) fibril_get_id();
    198195       
    199         if (fibril_get_sercount() != 0)
    200                 abort();
    201 
    202196        futex_down(&async_futex);
    203197        if (frw->writers) {
     
    224218        fibril_t *f = (fibril_t *) fibril_get_id();
    225219       
    226         if (fibril_get_sercount() != 0)
    227                 abort();
    228 
    229220        futex_down(&async_futex);
    230221        if (frw->writers || frw->readers) {
     
    380371        if (timeout) {
    381372                getuptime(&wdata.to_event.expires);
    382                 tv_add(&wdata.to_event.expires, timeout);
     373                tv_add_diff(&wdata.to_event.expires, timeout);
    383374                async_insert_timeout(&wdata);
    384375        }
     
    448439        int rc;
    449440
    450         fibril_mutex_lock(&timer->lock);
    451 
    452         while (true) {
    453                 while (timer->state != fts_active &&
    454                     timer->state != fts_cleanup) {
    455 
    456                         if (timer->state == fts_cleanup)
    457                                 break;
    458 
    459                         fibril_condvar_wait(&timer->cv, &timer->lock);
     441        fibril_mutex_lock(timer->lockp);
     442
     443        while (timer->state != fts_cleanup) {
     444                switch (timer->state) {
     445                case fts_not_set:
     446                case fts_fired:
     447                        fibril_condvar_wait(&timer->cv, timer->lockp);
     448                        break;
     449                case fts_active:
     450                        rc = fibril_condvar_wait_timeout(&timer->cv,
     451                            timer->lockp, timer->delay);
     452                        if (rc == ETIMEOUT && timer->state == fts_active) {
     453                                timer->state = fts_fired;
     454                                timer->handler_fid = fibril_get_id();
     455                                fibril_mutex_unlock(timer->lockp);
     456                                timer->fun(timer->arg);
     457                                fibril_mutex_lock(timer->lockp);
     458                                timer->handler_fid = 0;
     459                        }
     460                        break;
     461                case fts_cleanup:
     462                case fts_clean:
     463                        assert(false);
     464                        break;
    460465                }
    461 
    462                 if (timer->state == fts_cleanup)
    463                         break;
    464 
    465                 rc = fibril_condvar_wait_timeout(&timer->cv, &timer->lock,
    466                     timer->delay);
    467                 if (rc == ETIMEOUT) {
    468                         timer->state = fts_fired;
    469                         fibril_mutex_unlock(&timer->lock);
    470                         timer->fun(timer->arg);
    471                         fibril_mutex_lock(&timer->lock);
    472                 }
    473         }
    474 
    475         fibril_mutex_unlock(&timer->lock);
     466        }
     467
     468        /* Acknowledge timer fibril has finished cleanup. */
     469        timer->state = fts_clean;
     470        fibril_condvar_broadcast(&timer->cv);
     471        fibril_mutex_unlock(timer->lockp);
     472
    476473        return 0;
    477474}
     
    481478 * @return              New timer on success, @c NULL if out of memory.
    482479 */
    483 fibril_timer_t *fibril_timer_create(void)
     480fibril_timer_t *fibril_timer_create(fibril_mutex_t *lock)
    484481{
    485482        fid_t fid;
     
    501498        timer->fibril = fid;
    502499        timer->state = fts_not_set;
     500        timer->lockp = (lock != NULL) ? lock : &timer->lock;
    503501
    504502        fibril_add_ready(fid);
    505 
    506503        return timer;
    507504}
     
    513510void fibril_timer_destroy(fibril_timer_t *timer)
    514511{
    515         fibril_mutex_lock(&timer->lock);
    516         assert(timer->state != fts_active);
     512        fibril_mutex_lock(timer->lockp);
     513        assert(timer->state == fts_not_set || timer->state == fts_fired);
     514
     515        /* Request timer fibril to terminate. */
    517516        timer->state = fts_cleanup;
    518517        fibril_condvar_broadcast(&timer->cv);
    519         fibril_mutex_unlock(&timer->lock);
     518
     519        /* Wait for timer fibril to terminate */
     520        while (timer->state != fts_clean)
     521                fibril_condvar_wait(&timer->cv, timer->lockp);
     522        fibril_mutex_unlock(timer->lockp);
     523
     524        free(timer);
    520525}
    521526
     
    533538    fibril_timer_fun_t fun, void *arg)
    534539{
    535         fibril_mutex_lock(&timer->lock);
     540        fibril_mutex_lock(timer->lockp);
     541        fibril_timer_set_locked(timer, delay, fun, arg);
     542        fibril_mutex_unlock(timer->lockp);
     543}
     544
     545/** Set locked timer.
     546 *
     547 * Set timer to execute a callback function after the specified
     548 * interval. Must be called when the timer is locked.
     549 *
     550 * @param timer         Timer
     551 * @param delay         Delay in microseconds
     552 * @param fun           Callback function
     553 * @param arg           Argument for @a fun
     554 */
     555void fibril_timer_set_locked(fibril_timer_t *timer, suseconds_t delay,
     556    fibril_timer_fun_t fun, void *arg)
     557{
     558        assert(fibril_mutex_is_locked(timer->lockp));
     559        assert(timer->state == fts_not_set || timer->state == fts_fired);
    536560        timer->state = fts_active;
    537561        timer->delay = delay;
     
    539563        timer->arg = arg;
    540564        fibril_condvar_broadcast(&timer->cv);
    541         fibril_mutex_unlock(&timer->lock);
    542565}
    543566
     
    557580        fibril_timer_state_t old_state;
    558581
    559         fibril_mutex_lock(&timer->lock);
     582        fibril_mutex_lock(timer->lockp);
     583        old_state = fibril_timer_clear_locked(timer);
     584        fibril_mutex_unlock(timer->lockp);
     585
     586        return old_state;
     587}
     588
     589/** Clear locked timer.
     590 *
     591 * Clears (cancels) timer and returns last state of the timer.
     592 * This can be one of:
     593 *    - fts_not_set     If the timer has not been set or has been cleared
     594 *    - fts_active      Timer was set but did not fire
     595 *    - fts_fired       Timer fired
     596 * Must be called when the timer is locked.
     597 *
     598 * @param timer         Timer
     599 * @return              Last timer state
     600 */
     601fibril_timer_state_t fibril_timer_clear_locked(fibril_timer_t *timer)
     602{
     603        fibril_timer_state_t old_state;
     604
     605        assert(fibril_mutex_is_locked(timer->lockp));
     606
     607        while (timer->handler_fid != 0) {
     608                if (timer->handler_fid == fibril_get_id()) {
     609                        printf("Deadlock detected.\n");
     610                        stacktrace_print();
     611                        printf("Fibril %zx is trying to clear timer %p from "
     612                            "inside its handler %p.\n",
     613                            fibril_get_id(), timer, timer->fun);
     614                        abort();
     615                }
     616
     617                fibril_condvar_wait(&timer->cv, timer->lockp);
     618        }
     619
    560620        old_state = timer->state;
    561621        timer->state = fts_not_set;
     
    565625        timer->arg = NULL;
    566626        fibril_condvar_broadcast(&timer->cv);
    567         fibril_mutex_unlock(&timer->lock);
    568627
    569628        return old_state;
Note: See TracChangeset for help on using the changeset viewer.