Beispiel #1
0
int check_async_ready(void)
{
    ErlAsync* a;
    int count = 0;

    erts_mtx_lock(&async_ready_mtx);
    a = async_ready_list;
    async_ready_list = NULL;
    erts_mtx_unlock(&async_ready_mtx);

    while(a != NULL) {
	ErlAsync* a_next = a->next;
	/* Every port not dead */
	Port *p = erts_id2port_sflgs(a->port,
				     NULL,
				     0,
				     ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP);
	if (!p) {
	    if (a->async_free)
		(*a->async_free)(a->async_data);
	}
	else {
	    count++;
	    if (async_ready(p, a->async_data)) {
		if (a->async_free != NULL)
		    (*a->async_free)(a->async_data);
	    }
	    async_detach(a->hndl);
	    erts_port_release(p);
	}
	erts_free(ERTS_ALC_T_ASYNC, (void *) a);
	a = a_next;
    }
    return count;
}
Beispiel #2
0
static ERTS_INLINE void call_async_ready(ErtsAsync *a)
{
#if ERTS_USE_ASYNC_READY_Q
    Port *p = erts_id2port_sflgs(a->port,
				 NULL,
				 0,
				 ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP);
#else
    Port *p = erts_thr_id2port_sflgs(a->port,
				     ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP);
#endif
    if (!p) {
	if (a->async_free)
	    a->async_free(a->async_data);
    }
    else {
	if (async_ready(p, a->async_data)) {
	    if (a->async_free)
		a->async_free(a->async_data);
	}
#if ERTS_USE_ASYNC_READY_Q
	erts_port_release(p);
#else
	erts_thr_port_release(p);
#endif
    }
    if (a->pdl)
	driver_pdl_dec_refc(a->pdl);
    if (a->hndl)
	erts_ddll_dereference_driver(a->hndl);
}
Beispiel #3
0
int check_async_ready(void)
{
#ifdef USE_THREADS
    ErtsAsyncReadyCallback *cbs;
#endif
    ErlAsync* a;
    int count = 0;

    erts_mtx_lock(&async_ready_mtx);
    a = async_ready_list;
    async_ready_list = NULL;
#ifdef USE_THREADS
    cbs = callbacks;
#endif
    erts_mtx_unlock(&async_ready_mtx);

    while(a != NULL) {
        ErlAsync* a_next = a->next;
        /* Every port not dead */
        Port *p = erts_id2port_sflgs(a->port,
                                     NULL,
                                     0,
                                     ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP);
        if (!p) {
            if (a->async_free)
                (*a->async_free)(a->async_data);
        }
        else {
            count++;
            if (async_ready(p, a->async_data)) {
                if (a->async_free != NULL)
                    (*a->async_free)(a->async_data);
            }
            async_detach(a->hndl);
            erts_port_release(p);
        }
        erts_free(ERTS_ALC_T_ASYNC, (void *) a);
        a = a_next;
    }
#ifdef USE_THREADS
    for (; cbs; cbs = cbs->next)
        (*cbs->callback)();
#endif
    return count;
}
Beispiel #4
0
/*
** Schedule async_invoke on a worker thread
** NOTE will be syncrounous when threads are unsupported
** return values:
**  0  completed
**  -1 error
**  N  handle value (used with async_cancel)
**  arguments:
**      ix             driver index
**      key            pointer to secedule queue (NULL means round robin)
**      async_invoke   function to run in thread
**      async_data     data to pass to invoke function
**      async_free     function for relase async_data in case of failure
*/
long driver_async(ErlDrvPort ix, unsigned int* key,
                  void (*async_invoke)(void*), void* async_data,
                  void (*async_free)(void*))
{
    ErlAsync* a = (ErlAsync*) erts_alloc(ERTS_ALC_T_ASYNC, sizeof(ErlAsync));
    Port* prt = erts_drvport2port(ix);
    long id;
    unsigned int qix;


    if (!prt)
        return -1;

    ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));

    a->next = NULL;
    a->prev = NULL;
    a->hndl = (DE_Handle*)prt->drv_ptr->handle;
    a->port = prt->id;
    a->pdl = NULL;
    a->async_data = async_data;
    a->async_invoke = async_invoke;
    a->async_free = async_free;

    erts_smp_spin_lock(&async_id_lock);
    async_id = (async_id + 1) & 0x7fffffff;
    if (async_id == 0)
        async_id++;
    id = async_id;
    erts_smp_spin_unlock(&async_id_lock);

    a->async_id = id;

    if (key == NULL) {
        qix = (erts_async_max_threads > 0)
              ? (id % erts_async_max_threads) : 0;
    }
    else {
        qix = (erts_async_max_threads > 0) ?
              (*key % erts_async_max_threads) : 0;
        *key = qix;
    }
#ifdef USE_THREADS
    if (erts_async_max_threads > 0) {
        if (prt->port_data_lock) {
            driver_pdl_inc_refc(prt->port_data_lock);
            a->pdl = prt->port_data_lock;
        }
        async_add(a, &async_q[qix]);
        return id;
    }
#endif

    (*a->async_invoke)(a->async_data);

    if (async_ready(prt, a->async_data)) {
        if (a->async_free != NULL)
            (*a->async_free)(a->async_data);
    }
    erts_free(ERTS_ALC_T_ASYNC, (void *) a);

    return id;
}
Beispiel #5
0
static void* async_main(void* arg)
{
    AsyncQueue* q = (AsyncQueue*) arg;

#ifdef ERTS_ENABLE_LOCK_CHECK
    {
        char buf[27];
        erts_snprintf(&buf[0], 27, "async %d", q->no);
        erts_lc_set_thread_name(&buf[0]);
    }
#endif

    while(1) {
        ErlAsync* a = async_get(q);

        if (a->port == NIL) { /* TIME TO DIE SIGNAL */
            erts_free(ERTS_ALC_T_ASYNC, (void *) a);
            break;
        }
        else {
            (*a->async_invoke)(a->async_data);
            /* Major problem if the code for async_invoke
               or async_free is removed during a blocking operation */
#ifdef ERTS_SMP
            {
                Port *p;
                p = erts_id2port_sflgs(a->port,
                                       NULL,
                                       0,
                                       ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP);
                if (!p) {
                    if (a->async_free)
                        (*a->async_free)(a->async_data);
                }
                else {
                    if (async_ready(p, a->async_data)) {
                        if (a->async_free)
                            (*a->async_free)(a->async_data);
                    }
                    async_detach(a->hndl);
                    erts_port_release(p);
                }
                if (a->pdl) {
                    driver_pdl_dec_refc(a->pdl);
                }
                erts_free(ERTS_ALC_T_ASYNC, (void *) a);
            }
#else
            if (a->pdl) {
                driver_pdl_dec_refc(a->pdl);
            }
            erts_mtx_lock(&async_ready_mtx);
            a->next = async_ready_list;
            async_ready_list = a;
            erts_mtx_unlock(&async_ready_mtx);
            sys_async_ready(q->hndl);
#endif
        }
    }

    return NULL;
}
Beispiel #6
0
/*
** Schedule async_invoke on a worker thread
** NOTE will be syncrounous when threads are unsupported
** return values:
**  0  completed 
**  -1 error
**  N  handle value
**  arguments:
**      ix             driver index 
**      key            pointer to secedule queue (NULL means round robin)
**      async_invoke   function to run in thread
**      async_data     data to pass to invoke function
**      async_free     function for relase async_data in case of failure
*/
long driver_async(ErlDrvPort ix, unsigned int* key,
		  void (*async_invoke)(void*), void* async_data,
		  void (*async_free)(void*))
{
    ErtsAsync* a;
    Port* prt;
    long id;
    unsigned int qix;
#if ERTS_USE_ASYNC_READY_Q
    Uint sched_id;
    ERTS_MSACC_PUSH_STATE();

    sched_id = erts_get_scheduler_id();
    if (!sched_id)
	sched_id = 1;
#else
    ERTS_MSACC_PUSH_STATE();
#endif

    prt = erts_drvport2port(ix);
    if (prt == ERTS_INVALID_ERL_DRV_PORT)
	return -1;

    ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));

    a = (ErtsAsync*) erts_alloc(ERTS_ALC_T_ASYNC, sizeof(ErtsAsync));

#if ERTS_USE_ASYNC_READY_Q
    a->sched_id = sched_id;
#endif
    a->hndl = (DE_Handle*)prt->drv_ptr->handle;
    a->port = prt->common.id;
    a->pdl = NULL;
    a->async_data = async_data;
    a->async_invoke = async_invoke;
    a->async_free = async_free;

    if (!async)
	id = 0;
    else {
	do {
	    id = erts_atomic_inc_read_nob(&async->init.data.id);
	} while (id == 0);
	if (id < 0)
	    id *= -1;
	ASSERT(id > 0);
    }

    a->async_id = id;

    if (key == NULL) {
	qix = (erts_async_max_threads > 0)
	    ? (id % erts_async_max_threads) : 0;
    }
    else {
	qix = (erts_async_max_threads > 0) ? 
	    (*key % erts_async_max_threads) : 0;
	*key = qix;
    }
#ifdef USE_THREADS
    if (erts_async_max_threads > 0) {
	if (prt->port_data_lock) {
	    driver_pdl_inc_refc(prt->port_data_lock);
	    a->pdl = prt->port_data_lock;
	}
	async_add(a, async_q(qix));
	return id;
    }
#endif
    
    ERTS_MSACC_SET_STATE_CACHED(ERTS_MSACC_STATE_PORT);
    (*a->async_invoke)(a->async_data);
    ERTS_MSACC_POP_STATE();

    if (async_ready(prt, a->async_data)) {
	if (a->async_free != NULL) {
            ERTS_MSACC_SET_STATE_CACHED(ERTS_MSACC_STATE_PORT);
	    (*a->async_free)(a->async_data);
            ERTS_MSACC_POP_STATE();
        }
    }
    erts_free(ERTS_ALC_T_ASYNC, (void *) a);

    return id;
}