static ERL_NIF_TERM open_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { posix_errno_t posix_errno; efile_data_t *d; ErlNifPid controlling_process; enum efile_modes_t modes; ERL_NIF_TERM result; efile_path_t path; if(argc != 2 || !enif_is_list(env, argv[1])) { return enif_make_badarg(env); } modes = efile_translate_modelist(env, argv[1]); if((posix_errno = efile_marshal_path(env, argv[0], &path))) { return posix_error_to_tuple(env, posix_errno); } else if((posix_errno = efile_open(&path, modes, efile_resource_type, &d))) { return posix_error_to_tuple(env, posix_errno); } result = enif_make_resource(env, d); enif_release_resource(d); enif_self(env, &controlling_process); if(enif_monitor_process(env, d, &controlling_process, &d->monitor)) { return posix_error_to_tuple(env, EINVAL); } return enif_make_tuple2(env, am_ok, result); }
static ERL_NIF_TERM open_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { posix_errno_t posix_errno; efile_data_t *d; ErlNifPid controlling_process; enum efile_modes_t modes; ERL_NIF_TERM result; efile_path_t path; ASSERT(argc == 2); if(!enif_is_list(env, argv[1])) { return enif_make_badarg(env); } modes = efile_translate_modelist(env, argv[1]); if((posix_errno = efile_marshal_path(env, argv[0], &path))) { return posix_error_to_tuple(env, posix_errno); } else if((posix_errno = efile_open(&path, modes, efile_resource_type, &d))) { return posix_error_to_tuple(env, posix_errno); } enif_self(env, &controlling_process); if(enif_monitor_process(env, d, &controlling_process, &d->monitor)) { /* We need to close the file manually as we haven't registered a * destructor. */ posix_errno_t ignored; erts_atomic32_set_acqb(&d->state, EFILE_STATE_CLOSED); efile_close(d, &ignored); return posix_error_to_tuple(env, EINVAL); } /* Note that we do not call enif_release_resource at this point. While it's * normally safe to leave resource management to the GC, efile_close is a * blocking operation which must not be done in the GC callback, and we * can't defer it as the resource is gone as soon as it returns. * * We instead keep the resource alive until efile_close is called, after * which it's safe to leave things to the GC. If the controlling process * were to die before the user had a chance to close their file, the above * monitor will tell the erts_prim_file process to close it for them. */ result = enif_make_resource(env, d); return enif_make_tuple2(env, am_ok, result); }