static ERL_NIF_TERM close_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { enum efile_state_t previous_state; efile_data_t *d; ASSERT(argc == 1); if(!get_file_data(env, argv[0], &d)) { return enif_make_badarg(env); } previous_state = erts_atomic32_cmpxchg_acqb(&d->state, EFILE_STATE_CLOSED, EFILE_STATE_IDLE); if(previous_state == EFILE_STATE_IDLE) { posix_errno_t error; enif_demonitor_process(env, d, &d->monitor); if(!efile_close(d, &error)) { return posix_error_to_tuple(env, error); } return am_ok; } else { /* CLOSE_PENDING should be impossible at this point since it requires * a transition from BUSY; the only valid state here is CLOSED. */ ASSERT(previous_state == EFILE_STATE_CLOSED); return posix_error_to_tuple(env, EINVAL); } }
static ERL_NIF_TERM close_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { enum efile_state_t previous_state; ASSERT(argc == 0); previous_state = erts_atomic32_cmpxchg_acqb(&d->state, EFILE_STATE_CLOSED, EFILE_STATE_BUSY); ASSERT(previous_state == EFILE_STATE_CLOSE_PENDING || previous_state == EFILE_STATE_BUSY); if(previous_state == EFILE_STATE_BUSY) { enif_demonitor_process(env, d, &d->monitor); if(!efile_close(d)) { return posix_error_to_tuple(env, d->posix_errno); } } return am_ok; }