aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/doc/src/erl_nif.xml6
-rw-r--r--erts/emulator/beam/erl_nif.c5
-rw-r--r--erts/emulator/beam/erl_nif.h16
-rw-r--r--erts/emulator/beam/global.h2
-rw-r--r--erts/emulator/sys/common/erl_check_io.c8
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c65
6 files changed, 53 insertions, 49 deletions
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index e7073a962f..94aff7c67b 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -718,10 +718,12 @@ typedef void ErlNifResourceDtor(ErlNifEnv* env, void* obj);</code>
<tag><marker id="ErlNifResourceStop"/><c>ErlNifResourceStop</c></tag>
<item>
<code type="none">
-typedef void ErlNifResourceStop(ErlNifEnv* env, void* obj);</code>
+typedef void ErlNifResourceStop(ErlNifEnv* env, void* obj, ErlNifEvent event, int is_direct_call);</code>
<p>The function prototype of a resource stop function,
called on the behalf of <seealso marker="#enif_select">
- enif_select</seealso>.</p>
+ enif_select</seealso>. <c>obj</c> is the resource, <c>event</c> is OS event,
+ <c>is_direct_call</c> is true if the call is made directly from <c>enif_select</c>
+ or false if it is a scheduled call (potentially from another thread).</p>
</item>
<tag><marker id="ErlNifCharEncoding"/><c>ErlNifCharEncoding</c></tag>
<item>
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 27abba7cfd..4e41944ccb 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -2124,12 +2124,13 @@ static void nif_resource_dtor(Binary* bin)
}
}
-void erts_resource_stop(ErlNifResource* resource)
+void erts_resource_stop(ErlNifResource* resource, ErlNifEvent e,
+ int is_direct_call)
{
struct enif_msg_environment_t msg_env;
ASSERT(resource->type->stop);
pre_nif_noproc(&msg_env, resource->type->owner, NULL);
- resource->type->stop(&msg_env.env, resource->data);
+ resource->type->stop(&msg_env.env, resource->data, e, is_direct_call);
post_nif_noproc(&msg_env);
}
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index bf0f7b1f15..78e0fa1864 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -138,18 +138,18 @@ typedef struct
void* ref_bin;
}ErlNifBinary;
-typedef struct {
- void (*dtor)(ErlNifEnv* env, void* obj);
- void (*stop)(ErlNifEnv* env, void* obj); /* at ERL_NIF_SELECT_STOP event */
-} ErlNifResourceTypeInit;
+//#ifndef ERL_SYS_DRV
+typedef int ErlNifEvent; /* An event to be selected on. */
+//#endif
typedef struct enif_resource_type_t ErlNifResourceType;
typedef void ErlNifResourceDtor(ErlNifEnv*, void*);
-typedef void ErlNifResourceStop(ErlNifEnv*, void*);
+typedef void ErlNifResourceStop(ErlNifEnv*, void*, ErlNifEvent, int is_direct_call);
-//#ifndef ERL_SYS_DRV
-typedef int ErlNifEvent; /* An event to be selected on. */
-//#endif
+typedef struct {
+ ErlNifResourceDtor* dtor;
+ ErlNifResourceStop* stop; /* at ERL_NIF_SELECT_STOP event */
+} ErlNifResourceTypeInit;
typedef enum
{
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 5c5693a315..2decb56544 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -95,7 +95,7 @@ extern void erts_pre_dirty_nif(ErtsSchedulerData *,
struct erl_module_nif*);
extern void erts_post_dirty_nif(struct enif_environment_t* env);
#endif
-extern void erts_resource_stop(ErlNifResource* resource);
+extern void erts_resource_stop(ErlNifResource*, ErlNifEvent, int is_direct_call);
extern Eterm erts_nif_taints(Process* p);
extern void erts_print_nif_taints(fmtfn_t to, void* to_arg);
void erts_unload_nif(struct erl_module_nif* nif);
diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c
index aeda49b2c6..a533a10c22 100644
--- a/erts/emulator/sys/common/erl_check_io.c
+++ b/erts/emulator/sys/common/erl_check_io.c
@@ -450,7 +450,7 @@ forget_removed(struct pollset_info* psi)
}
}
if (resource) {
- erts_resource_stop(resource);
+ erts_resource_stop(resource, (ErlNifEvent)fd, 0);
enif_release_resource(resource->data);
}
@@ -1436,7 +1436,7 @@ done:
done_unknown:
erts_smp_mtx_unlock(fd_mtx(fd));
if (call_stop) {
- erts_resource_stop(resource);
+ erts_resource_stop(resource, (ErlNifEvent)fd, 1);
if (call_stop == CALL_STOP_AND_RELEASE) {
enif_release_resource(resource->data);
}
@@ -2141,6 +2141,10 @@ ERTS_CIO_EXPORT(erts_check_io_interrupt_timed)(int set,
ERTS_CIO_POLL_INTR_TMD(pollset.ps, set, timeout_time);
}
+/*
+ * Number of ignored events, for a lingering fd added by enif_select(),
+ * until we deselect fd-event from pollset.
+ */
#define ERTS_NIF_DELAYED_DESELECT 20
void
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index f6ccd3e6ba..878a9ffda9 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -108,13 +108,14 @@ struct binary_resource {
static ErlNifResourceType* fd_resource_type;
static void fd_resource_dtor(ErlNifEnv* env, void* obj);
-static void fd_resource_stop(ErlNifEnv* env, void* obj);
+static void fd_resource_stop(ErlNifEnv* env, void* obj, ErlNifEvent, int);
static ErlNifResourceTypeInit fd_rt_init = {
fd_resource_dtor,
fd_resource_stop
};
struct fd_resource {
int fd;
+ int was_selected;
};
@@ -1128,10 +1129,6 @@ static ERL_NIF_TERM make_term_string(struct make_term_info* mti, int n)
{
return enif_make_string(mti->dst_env, "Hello!", ERL_NIF_LATIN1);
}
-static ERL_NIF_TERM make_term_ref(struct make_term_info* mti, int n)
-{
- return enif_make_ref(mti->dst_env);
-}
static ERL_NIF_TERM make_term_sub_binary(struct make_term_info* mti, int n)
{
ERL_NIF_TERM orig;
@@ -1239,7 +1236,6 @@ static Make_term_Func* make_funcs[] = {
make_term_atom,
make_term_existing_atom,
make_term_string,
- //make_term_ref,
make_term_sub_binary,
make_term_uint,
make_term_long,
@@ -2032,26 +2028,23 @@ static ERL_NIF_TERM format_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
}
-static int get_fd(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifEvent* fd)
+static int get_fd(ErlNifEnv* env, ERL_NIF_TERM term, struct fd_resource** rsrc)
{
- struct fd_resource* rsrc;
-
- if (!enif_get_resource(env, term, fd_resource_type, (void**)&rsrc)) {
+ if (!enif_get_resource(env, term, fd_resource_type, (void**)rsrc)) {
return 0;
}
- *fd = rsrc->fd;
return 1;
}
static ERL_NIF_TERM select_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- ErlNifEvent e;
+ struct fd_resource* fdr;
enum ErlNifSelectFlags mode;
void* obj;
ERL_NIF_TERM ref;
int retval;
- if (!get_fd(env, argv[0], &e)
+ if (!get_fd(env, argv[0], &fdr)
|| !enif_get_uint(env, argv[1], &mode)
|| !enif_get_resource(env, argv[2], fd_resource_type, &obj))
{
@@ -2060,7 +2053,8 @@ static ERL_NIF_TERM select_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
ref = argv[3];
- retval = enif_select(env, e, mode, obj, ref);
+ fdr->was_selected = 1;
+ retval = enif_select(env, fdr->fd, mode, obj, ref);
return enif_make_int(env, retval);
}
@@ -2070,7 +2064,6 @@ static ERL_NIF_TERM pipe_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
struct fd_resource* read_rsrc;
struct fd_resource* write_rsrc;
ERL_NIF_TERM read_fd, write_fd;
- unsigned char *inp, *outp;
int fds[2], flags;
if (pipe(fds) < 0)
@@ -2099,16 +2092,16 @@ static ERL_NIF_TERM pipe_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
static ERL_NIF_TERM write_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- ErlNifEvent fd;
+ struct fd_resource* fdr;
ErlNifBinary bin;
int n, written = 0;
- if (!get_fd(env, argv[0], &fd)
+ if (!get_fd(env, argv[0], &fdr)
|| !enif_inspect_binary(env, argv[1], &bin))
return enif_make_badarg(env);
for (;;) {
- n = write(fd, bin.data + written, bin.size - written);
+ n = write(fdr->fd, bin.data + written, bin.size - written);
if (n >= 0) {
written += n;
if (written == bin.size) {
@@ -2129,19 +2122,19 @@ static ERL_NIF_TERM write_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
static ERL_NIF_TERM read_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- ErlNifEvent fd;
+ struct fd_resource* fdr;
unsigned char* buf;
- int n, count, nread = 0;
+ int n, count;
ERL_NIF_TERM res;
- if (!get_fd(env, argv[0], &fd)
+ if (!get_fd(env, argv[0], &fdr)
|| !enif_get_int(env, argv[1], &count) || count < 1)
return enif_make_badarg(env);
buf = enif_make_new_binary(env, count, &res);
for (;;) {
- n = read(fd, buf, count);
+ n = read(fdr->fd, buf, count);
if (n > 0) {
if (n < count) {
res = enif_make_sub_binary(env, res, 0, n);
@@ -2165,29 +2158,33 @@ static ERL_NIF_TERM read_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
static ERL_NIF_TERM is_closed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- ErlNifEvent fd;
+ struct fd_resource* fdr;
- if (!get_fd(env, argv[0], &fd))
+ if (!get_fd(env, argv[0], &fdr))
return enif_make_badarg(env);
- return fd < 0 ? atom_true : atom_false;
+ return fdr->fd < 0 ? atom_true : atom_false;
}
static void fd_resource_dtor(ErlNifEnv* env, void* obj)
{
- struct fd_resource* rsrc = (struct fd_resource*)obj;
+ struct fd_resource* fdr = (struct fd_resource*)obj;
resource_dtor(env, obj);
- if (rsrc->fd >= 0)
- close(rsrc->fd);
+ if (fdr->fd >= 0) {
+ assert(!fdr->was_selected);
+ close(fdr->fd);
+ }
}
-static void fd_resource_stop(ErlNifEnv* env, void* obj)
+static void fd_resource_stop(ErlNifEnv* env, void* obj, ErlNifEvent fd,
+ int is_direct_call)
{
- struct fd_resource* rsrc = (struct fd_resource*)obj;
- if (rsrc->fd >= 0) {
- close(rsrc->fd);
- rsrc->fd = -1; /* thread safety ? */
- }
+ struct fd_resource* fdr = (struct fd_resource*)obj;
+ assert(fd == fdr->fd);
+ assert(fd >= 0);
+ close(fd);
+ fdr->fd = -1; /* thread safety ? */
+ fdr->was_selected = 0;
}