Ejemplo n.º 1
0
static void owner_death_callback(ErlNifEnv* env, void* obj, ErlNifPid* pid, ErlNifMonitor* mon) {
    efile_data_t *d = (efile_data_t*)obj;

    (void)env;
    (void)pid;
    (void)mon;

    for(;;) {
        enum efile_state_t previous_state;

        previous_state = erts_atomic32_cmpxchg_acqb(&d->state,
            EFILE_STATE_CLOSED, EFILE_STATE_IDLE);

        switch(previous_state) {
        case EFILE_STATE_IDLE:
            efile_close(d);
            return;
        case EFILE_STATE_CLOSE_PENDING:
        case EFILE_STATE_CLOSED:
            /* We're either already closed or managed to mark ourselves for
             * closure in the previous iteration. */
            return;
        case EFILE_STATE_BUSY:
            /* Schedule ourselves to be closed once the current operation
             * finishes, retrying the [IDLE -> CLOSED] transition in case we
             * narrowly passed the [BUSY -> IDLE] one. */
            erts_atomic32_cmpxchg_nob(&d->state,
                EFILE_STATE_CLOSE_PENDING, EFILE_STATE_BUSY);
            break;
        }
    }
}
Ejemplo n.º 2
0
static void owner_death_callback(ErlNifEnv* env, void* obj, ErlNifPid* pid, ErlNifMonitor* mon) {
    efile_data_t *d = (efile_data_t*)obj;

    (void)env;
    (void)pid;
    (void)mon;

    for(;;) {
        enum efile_state_t previous_state;

        previous_state = erts_atomic32_cmpxchg_acqb(&d->state,
            EFILE_STATE_CLOSED, EFILE_STATE_IDLE);

        switch(previous_state) {
        case EFILE_STATE_IDLE:
            {
                /* We cannot close the file here as that could block a normal
                 * scheduler, so we tell erts_prim_file to do it for us.
                 *
                 * This can in turn become a bottleneck (especially in cases
                 * like NFS failure), but it's less problematic than blocking
                 * thread progress. */
                ERL_NIF_TERM message, file_ref;

                file_ref = enif_make_resource(env, d);
                message = enif_make_tuple2(env, am_close, file_ref);

                if(!enif_send(env, &erts_prim_file_pid, NULL, message)) {
                    ERTS_INTERNAL_ERROR("Failed to defer prim_file close.");
                }

                return;
            }
        case EFILE_STATE_CLOSE_PENDING:
        case EFILE_STATE_CLOSED:
            /* We're either already closed or managed to mark ourselves for
             * closure in the previous iteration. */
            return;
        case EFILE_STATE_BUSY:
            /* Schedule ourselves to be closed once the current operation
             * finishes, retrying the [IDLE -> CLOSED] transition in case we
             * narrowly passed the [BUSY -> IDLE] one. */
            erts_atomic32_cmpxchg_nob(&d->state,
                EFILE_STATE_CLOSE_PENDING, EFILE_STATE_BUSY);
            break;
        }
    }
}