Ejemplo n.º 1
0
long gu_to_self_cancel(gu_to_t *to, gu_seqno_t seqno)
{
    long         err = 0;
    to_waiter_t *w;

    assert (seqno >= 0);

    if ((err = gu_mutex_lock (&to->lock))) {
        gu_fatal("Mutex lock failed (%d): %s", err, strerror(err));
        abort();
    }

    if ((w = to_get_waiter (to, seqno)) == NULL) {
        gu_mutex_unlock(&to->lock);
        return -EAGAIN;
    }        
    /* we have a valid waiter now */

    if (seqno > to->seqno) { // most probable case
        w->state = CANCELED;
    }
    else if (seqno == to->seqno) {
        // have to wake the next waiter as if we grabbed and now releasing TO
        to_release_and_wake_next (to, w);
    }
    else { // (seqno < to->seqno)
        // This waiter must have been canceled or even released by preceding
        // waiter. Do nothing.
    }
    
    gu_mutex_unlock(&to->lock);
    
    return err;
}
Ejemplo n.º 2
0
long gu_to_interrupt (gu_to_t *to, gu_seqno_t seqno)
{
    long rcode = 0;
    long err;
    to_waiter_t *w;

    assert (seqno >= 0);

    if ((err = gu_mutex_lock (&to->lock))) {
        gu_fatal("Mutex lock failed (%d): %s", err, strerror(err));
        abort();
    }
    if (seqno >= to->seqno) {
        if ((w = to_get_waiter (to, seqno)) == NULL) {
            gu_mutex_unlock(&to->lock);
            return -EAGAIN;
        }        
        /* we have a valid waiter now */

        switch (w->state) {
        case HOLDER:
            gu_debug ("trying to interrupt in use seqno: seqno = %llu, "
                      "TO seqno = %llu", seqno, to->seqno);
            /* gu_mutex_unlock (&to->lock); */
            rcode = -ERANGE;
            break;
        case CANCELED:
            gu_debug ("trying to interrupt canceled seqno: seqno = %llu, "
                      "TO seqno = %llu", seqno, to->seqno);
            /* gu_mutex_unlock (&to->lock); */
            rcode = -ERANGE;
            break;
        case WAIT:
            gu_debug ("signaling to interrupt wait seqno: seqno = %llu, "
                      "TO seqno = %llu", seqno, to->seqno);
            rcode    = to_wake_waiter (w);
        case RELEASED:
            w->state = INTERRUPTED;
            break;
        case INTERRUPTED:
            gu_debug ("TO waiter interrupt already seqno: seqno = %llu, "
                      "TO seqno = %llu", seqno, to->seqno);
            break;
        }
    } else {
        gu_debug ("trying to interrupt used seqno: cancel seqno = %llu, "
                  "TO seqno = %llu", seqno, to->seqno);
        /* gu_mutex_unlock (&to->lock); */
        rcode = -ERANGE;
    }

    gu_mutex_unlock (&to->lock);
    return rcode;
}
long
gcs_sm_close (gcs_sm_t* sm)
{
    gu_info ("Closing send monitor...");

    if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort();

    sm->ret = -EBADFD;

    if (sm->pause) _gcs_sm_continue_common (sm);

    gu_cond_t cond;
    gu_cond_init (&cond, NULL);

    // in case the queue is full
    while (sm->users >= (long)sm->wait_q_len) {
        gu_mutex_unlock (&sm->lock);
        usleep(1000);
        gu_mutex_lock (&sm->lock);
    }

    while (sm->users > 0) { // wait for cleared queue
        sm->users++;
        GCS_SM_INCREMENT(sm->wait_q_tail);
        _gcs_sm_enqueue_common (sm, &cond);
        sm->users--;
        GCS_SM_INCREMENT(sm->wait_q_head);
    }

    gu_cond_destroy (&cond);

    gu_mutex_unlock (&sm->lock);

    gu_info ("Closed send monitor.");

    return 0;
}
void
gcs_sm_stats_get (gcs_sm_t*  sm,
                  int*       q_len,
                  double*    q_len_avg,
                  long long* paused_ns,
                  double*    paused_avg)
{
    gcs_sm_stats_t tmp;
    long long      now;
    bool           paused;

    if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort();

    *q_len = sm->users;
    tmp    = sm->stats;
    now    = gu_time_monotonic();
    paused = sm->pause;

    gu_mutex_unlock (&sm->lock);

    if (paused) { // taking sample in a middle of a pause
        tmp.paused_ns += now - tmp.pause_start;
    }
    *paused_ns = tmp.paused_ns;

    if (gu_likely(tmp.paused_ns >= 0)) {
        *paused_avg = ((double)(tmp.paused_ns - tmp.paused_sample)) /
                       (now - tmp.sample_start);
    }
    else {
        *paused_avg = -1.0;
    }

    if (gu_likely(tmp.send_q_len >= 0 && tmp.send_q_samples >= 0)){
        if (gu_likely(tmp.send_q_samples > 0)) {
            *q_len_avg = ((double)tmp.send_q_len) / tmp.send_q_samples;
        }
        else {
            *q_len_avg = 0.0;
        }
    }
    else {
        *q_len_avg = -1.0;
    }
}
long
gcs_sm_open (gcs_sm_t* sm)
{
    long ret = -1;

    if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort();

    if (-EBADFD == sm->ret)  /* closed */
    {
        sm->ret = 0;
    }
    ret = sm->ret;

    gu_mutex_unlock (&sm->lock);

    if (ret) { gu_error ("Can't open send monitor: wrong state %d", ret); }

    return ret;
}
void
gcs_sm_stats_flush(gcs_sm_t* sm)
{
    if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort();

    long long const now = gu_time_monotonic();

    sm->stats.sample_start = now;

    sm->stats.paused_sample = sm->stats.paused_ns;

    if (sm->pause) // append elapsed pause time
    {
        sm->stats.paused_sample  += now - sm->stats.pause_start;
    }

    sm->stats.send_q_len     = 0;
    sm->stats.send_q_samples = 0;

    gu_mutex_unlock (&sm->lock);
}
Ejemplo n.º 7
0
long gu_to_release (gu_to_t *to, gu_seqno_t seqno)
{
    long         err;
    to_waiter_t *w;

    assert (seqno >= 0);

    if ((err = gu_mutex_lock(&to->lock))) {
        gu_fatal("Mutex lock failed (%d): %s", err, strerror(err));
        abort();
    }

    if ((w = to_get_waiter (to, seqno)) == NULL) {
        gu_mutex_unlock(&to->lock);
        return -EAGAIN;
    }        
    /* we have a valid waiter now */
    
    if (seqno == to->seqno) {
        to_release_and_wake_next (to, w);
    } else if (seqno > to->seqno) {
        if (w->state != CANCELED) {
            gu_fatal("Illegal state in premature release: %d", w->state);
            abort();
        }
        /* Leave state CANCELED so that real releaser can iterate  */
    } else {
        /* */
        if (w->state != RELEASED) {
            gu_fatal("Outdated seqno and state not RELEASED: %d", w->state);
            abort();
        }
    }

    gu_mutex_unlock(&to->lock);

    return err;
}
Ejemplo n.º 8
0
long gu_to_destroy (gu_to_t** to)
{
    gu_to_t *t = *to;
    long      ret;
    ssize_t    i;

    gu_mutex_lock (&t->lock);
    if (t->used) {
        gu_mutex_unlock (&t->lock);
        return -EBUSY;
    }
    
    for (i = 0; i < t->qlen; i++) {
        to_waiter_t *w = t->queue + i;
#ifdef TO_USE_SIGNAL
        if (gu_cond_destroy (&w->cond)) {
            // @todo: what if someone is waiting?
            gu_warn ("Failed to destroy condition %d. Should not happen", i);
        }
#else
        if (pthread_mutex_destroy (&w->mtx)) {
            // @todo: what if someone is waiting?
            gu_warn ("Failed to destroy mutex %d. Should not happen", i);
        }
#endif
    }    
    t->qlen = 0;
    
    gu_mutex_unlock (&t->lock);
    /* What else can be done here? */
    ret = gu_mutex_destroy (&t->lock);
    if (ret) return -ret; // application can retry

    gu_free (t->queue);
    gu_free (t);
    *to = NULL;
    return 0;
}
Ejemplo n.º 9
0
long gu_to_cancel (gu_to_t *to, gu_seqno_t seqno)
{
    long         err;
    to_waiter_t *w;

    assert (seqno >= 0);

    if ((err = gu_mutex_lock (&to->lock))) {
        gu_fatal("Mutex lock failed (%d): %s", err, strerror(err));
        abort();
    }
    
    // Check for queue overflow. This is totally unrecoverable. Abort.
    if ((w = to_get_waiter (to, seqno)) == NULL) {
        gu_mutex_unlock(&to->lock);
        abort();
    }        
    /* we have a valid waiter now */

    if ((seqno > to->seqno) || 
        (seqno == to->seqno && w->state != HOLDER)) {
        err = to_wake_waiter (w);
        w->state = CANCELED;
    } else if (seqno == to->seqno && w->state == HOLDER) {
        gu_warn("tried to cancel current TO holder, state %d seqno %llu",
                 w->state, seqno);
        err = -ECANCELED;
    } else {
        gu_warn("trying to cancel used seqno: state %d cancel seqno = %llu, "
                "TO seqno = %llu", w->state, seqno, to->seqno);
        err = -ECANCELED;        
    }
    
    gu_mutex_unlock (&to->lock);
    return err;
}
Ejemplo n.º 10
0
long gu_to_grab (gu_to_t* to, gu_seqno_t seqno)
{
    long err;
    to_waiter_t *w;

    assert (seqno >= 0);

    if ((err = gu_mutex_lock(&to->lock))) {
        gu_fatal("Mutex lock failed (%d): %s", err, strerror(err));
        abort();
    }

    if (seqno < to->seqno) {
        gu_mutex_unlock(&to->lock);
        return -ECANCELED;
    }

    if ((w = to_get_waiter (to, seqno)) == NULL) {
        gu_mutex_unlock(&to->lock);
        return -EAGAIN;
    }        
    /* we have a valid waiter now */

    switch (w->state) {
    case INTERRUPTED:
        w->state = RELEASED;
        err = -EINTR;
        break;
    case CANCELED:
        err = -ECANCELED;
        break;
    case RELEASED:
        if (seqno == to->seqno) {
            w->state = HOLDER;
        } else if (seqno < to->seqno) {
            gu_error("Trying to grab outdated seqno");
            err = -ECANCELED;
        } else { /* seqno > to->seqno, wait for my turn */
            w->state = WAIT;
            to->used++;
#ifdef TO_USE_SIGNAL
            gu_cond_wait(&w->cond, &to->lock);
#else
            pthread_mutex_lock (&w->mtx);
            pthread_mutex_unlock (&to->lock);
            pthread_mutex_lock (&w->mtx); // wait for unlock by other thread
            pthread_mutex_lock (&to->lock);
            pthread_mutex_unlock (&w->mtx);
#endif
            to->used--;
            switch (w->state) { 
            case WAIT:// should be most probable
                assert (seqno == to->seqno);
                w->state = HOLDER;
                break;
            case INTERRUPTED:
                w->state = RELEASED;
                err      = -EINTR;
                break;
            case CANCELED:
                err = -ECANCELED;
                break;
            case RELEASED:
                /* this waiter has been cancelled */
                assert(seqno < to->seqno);
                err = -ECANCELED;
                break;
            default:
                gu_fatal("Invalid cond wait exit state %d, seqno %llu(%llu)",
                         w->state, seqno, to->seqno);
                abort();
            }
        }
        break;
    default:
        gu_fatal("TO queue over wrap");
        abort();
    }
    
    gu_mutex_unlock(&to->lock);
    return err;
}
long gcs_fifo_lite_destroy (gcs_fifo_lite_t* f)
{
    if (f) {
	if (gu_mutex_lock (&f->lock)) { abort(); }

	if (f->destroyed) {
	    gu_mutex_unlock (&f->lock);
	    return -EALREADY;
	}

        f->closed    = true;
	f->destroyed = true;

	/* get rid of "put" threads waiting for lock or signal */
	while (pthread_cond_destroy (&f->put_cond)) {
            if (f->put_wait <= 0) {
                gu_fatal ("Can't destroy condition while nobody's waiting");
                abort();
            }
            f->put_wait = 0;
            gu_cond_broadcast (&f->put_cond);
	}

	while (f->used) {
	    /* there are some items in FIFO - and that means
	     * no gcs_fifo_lite_safe_get() is waiting on condition */
	    gu_mutex_unlock (&f->lock);
	    /* let them get remaining items from FIFO,
	     * we don't know how to deallocate them ourselves.
	     * unfortunately this may take some time */
	    usleep (10000); /* sleep a bit to avoid busy loop */
	    gu_mutex_lock (&f->lock);
	}
	f->length = 0;

	/* now all we have - "get" threads waiting for lock or signal */
	while (pthread_cond_destroy (&f->get_cond)) {
            if (f->get_wait <= 0) {
                gu_fatal ("Can't destroy condition while nobody's waiting");
                abort();
            }
            f->get_wait = 0;
            gu_cond_broadcast (&f->get_cond);
	}

	/* at this point there are only functions waiting for lock */
	gu_mutex_unlock (&f->lock);
	while (gu_mutex_destroy (&f->lock)) {
	    /* this should be fast provided safe get and safe put are
	     * wtitten correctly. They should immediately freak out. */
	    gu_mutex_lock   (&f->lock);
	    gu_mutex_unlock (&f->lock);
	}

	/* now nobody's waiting for anything */
	gu_free (f->queue);
	gu_free (f);
	return 0;
    }
    return -EINVAL;
}