aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
authorSteve Vinoski <[email protected]>2015-04-27 23:39:37 -0400
committerSteve Vinoski <[email protected]>2015-05-26 11:13:16 -0400
commit884afd8efb8672df2889df98b5b94f3dbb53952c (patch)
treef12032760444836964397d4a30869aed2a656c43 /erts
parent2f38cce79ae1bf318cdc8884bd74d1407778d91d (diff)
downloadotp-884afd8efb8672df2889df98b5b94f3dbb53952c.tar.gz
otp-884afd8efb8672df2889df98b5b94f3dbb53952c.tar.bz2
otp-884afd8efb8672df2889df98b5b94f3dbb53952c.zip
Enhance enif_has_pending_exception
Sverker Eriksson came up with the following idea: to handle a future ability for NIFs to raise more than just badarg exceptions, modify the recently-added enif_has_pending_exception function to take a second argument: a pointer to ERL_NIF_TERM. If this argument is a null pointer, ignore it. Otherwise, if the first argument, an ErlNifEnv*, has an associated exception, set the pointed-to ERL_NIF_TERM of the second argument to the value of the exception term. Add new tests and documentation for this modification.
Diffstat (limited to 'erts')
-rw-r--r--erts/doc/src/erl_nif.xml12
-rw-r--r--erts/emulator/beam/erl_nif.c5
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h2
-rw-r--r--erts/emulator/test/nif_SUITE.erl18
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c25
5 files changed, 41 insertions, 21 deletions
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index 4bad8b253c..155aee2f42 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -778,11 +778,17 @@ typedef enum {
and return true, or return false if <c>term</c> is not an unsigned integer or is
outside the bounds of type <c>unsigned long</c>.</p></desc>
</func>
- <func><name><ret>int</ret><nametext>enif_has_pending_exception(ErlNifEnv* env)</nametext></name>
+ <func><name><ret>int</ret><nametext>enif_has_pending_exception(ErlNifEnv* env, ERL_NIF_TERM* reason)</nametext></name>
<fsummary>Check if an exception has been raised.</fsummary>
<desc><p>Return true if a pending exception is associated
- with the environment <c>env</c>. The only possible exception is currently
- <c>badarg</c> (see <seealso marker="#enif_make_badarg">enif_make_badarg</seealso>).</p></desc>
+ with the environment <c>env</c>. If <c>reason</c> is a null pointer, ignore it.
+ Otherwise, if there's a pending exception associated with <c>env</c>, set the ERL_NIF_TERM
+ to which <c>reason</c> points to the value of the exception's term. For example, if
+ <seealso marker="#enif_make_badarg">enif_make_badarg</seealso> is called to set a
+ pending <c>badarg</c> exception, a subsequent call to <c>enif_has_pending_exception(env, &amp;reason)</c>
+ will set <c>reason</c> to the atom <c>badarg</c>, then return true.</p>
+ <p>See also: <seealso marker="#enif_make_badarg">enif_make_badarg</seealso>.</p>
+ </desc>
</func>
<func><name><ret>int</ret><nametext>enif_inspect_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term, ErlNifBinary* bin)</nametext></name>
<fsummary>Inspect the content of a binary</fsummary>
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 7876785a76..36da6519f7 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -741,8 +741,11 @@ Eterm enif_make_badarg(ErlNifEnv* env)
BIF_ERROR(env->proc, BADARG);
}
-int enif_has_pending_exception(ErlNifEnv* env)
+int enif_has_pending_exception(ErlNifEnv* env, ERL_NIF_TERM* reason)
{
+ if (env->exception_thrown && reason != NULL) {
+ *reason = am_badarg;
+ }
return env->exception_thrown;
}
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index bdcbb32c46..fe25c803ec 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -156,7 +156,7 @@ ERL_NIF_API_FUNC_DECL(int, enif_map_iterator_next, (ErlNifEnv *env, ErlNifMapIte
ERL_NIF_API_FUNC_DECL(int, enif_map_iterator_prev, (ErlNifEnv *env, ErlNifMapIterator *iter));
ERL_NIF_API_FUNC_DECL(int, enif_map_iterator_get_pair, (ErlNifEnv *env, ErlNifMapIterator *iter, ERL_NIF_TERM *key, ERL_NIF_TERM *value));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_schedule_nif,(ErlNifEnv*,const char*,int,ERL_NIF_TERM (*)(ErlNifEnv*,int,const ERL_NIF_TERM[]),int,const ERL_NIF_TERM[]));
-ERL_NIF_API_FUNC_DECL(int, enif_has_pending_exception, (ErlNifEnv *env));
+ERL_NIF_API_FUNC_DECL(int, enif_has_pending_exception, (ErlNifEnv *env, ERL_NIF_TERM* reason));
/*
** ADD NEW ENTRIES HERE (before this comment) !!!
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index c35c71dd5b..434d1c38d0 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -1387,7 +1387,7 @@ is_checks(Config) when is_list(Config) ->
self(), hd(erlang:ports()), [], [1,9,9,8],
{hejsan, "hejsan", [$h,"ejs",<<"an">>]}, -18446744073709551616.2e2),
try
- ?line error = check_is_exception(),
+ ?line check_is_exception(),
?line throw(expected_badarg)
catch
error:badarg ->
@@ -1599,9 +1599,9 @@ dirty_nif_exception(Config) when is_list(Config) ->
N when is_integer(N) ->
ensure_lib_loaded(Config),
try
- %% this checks that the expected exception
- %% occurs when the NIF returns the result
- %% of enif_make_badarg directly
+ %% this checks that the expected exception occurs when the
+ %% dirty NIF returns the result of enif_make_badarg
+ %% directly
call_dirty_nif_exception(1),
?t:fail(expected_badarg)
catch
@@ -1611,10 +1611,9 @@ dirty_nif_exception(Config) when is_list(Config) ->
ok
end,
try
- %% this checks that the expected exception
- %% occurs when the NIF calls enif_make_badarg
- %% at some point but then returns a value that
- %% isn't an exception
+ %% this checks that the expected exception occurs when the
+ %% dirty NIF calls enif_make_badarg at some point but then
+ %% returns a value that isn't an exception
call_dirty_nif_exception(0),
?t:fail(expected_badarg)
catch
@@ -1631,6 +1630,9 @@ dirty_nif_exception(Config) when is_list(Config) ->
nif_exception(Config) when is_list(Config) ->
ensure_lib_loaded(Config),
try
+ %% this checks that the expected exception occurs when the NIF
+ %% calls enif_make_badarg at some point but then tries to return a
+ %% value that isn't an exception
call_nif_exception(),
?t:fail(expected_badarg)
catch
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index 58d9a9a88c..95e361690f 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -883,16 +883,19 @@ static ERL_NIF_TERM check_is(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
*
* This function is separate from check_is because it calls enif_make_badarg
* and so it must return the badarg exception as its return value. Thus, the
- * badarg exception indicates success. Failure is indicated by returning an
- * error atom.
+ * badarg exception indicates success.
*/
static ERL_NIF_TERM check_is_exception(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
+ ERL_NIF_TERM badarg, exc_term;
ERL_NIF_TERM error_atom = enif_make_atom(env, "error");
- ERL_NIF_TERM badarg = enif_make_badarg(env);
- if (enif_is_exception(env, error_atom)) return error_atom;
- if (!enif_is_exception(env, badarg)) return error_atom;
- if (!enif_has_pending_exception(env)) return error_atom;
+ ERL_NIF_TERM badarg_atom = enif_make_atom(env, "badarg");
+ assert(!enif_is_exception(env, error_atom));
+ badarg = enif_make_badarg(env);
+ assert(enif_is_exception(env, badarg));
+ assert(enif_has_pending_exception(env, NULL));
+ assert(enif_has_pending_exception(env, &exc_term));
+ assert(enif_is_identical(exc_term, badarg_atom));
return badarg;
}
@@ -1621,7 +1624,7 @@ static ERL_NIF_TERM call_dirty_nif_exception(ErlNifEnv* env, int argc, const ERL
for (i = 1; i < 255; i++)
args[i] = enif_make_int(env, i);
return enif_schedule_nif(env, "call_dirty_nif_exception", ERL_NIF_DIRTY_JOB_CPU_BOUND,
- call_dirty_nif_exception, 255, argv);
+ call_dirty_nif_exception, 255, args);
}
case 2: {
int return_badarg_directly;
@@ -1660,7 +1663,13 @@ static ERL_NIF_TERM call_dirty_nif_zero_args(ErlNifEnv* env, int argc, const ERL
*/
static ERL_NIF_TERM call_nif_exception(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
+ ERL_NIF_TERM exc_term;
+ ERL_NIF_TERM badarg_atom = enif_make_atom(env, "badarg");
+
/* ignore return value */ enif_make_badarg(env);
+ assert(enif_has_pending_exception(env, NULL));
+ assert(enif_has_pending_exception(env, &exc_term));
+ assert(enif_is_identical(badarg_atom, exc_term));
return enif_make_atom(env, "ok");
}
@@ -1696,7 +1705,7 @@ static ERL_NIF_TERM call_nif_nan_or_inf(ErlNifEnv* env, int argc, const ERL_NIF_
}
res = enif_make_double(env, val);
assert(enif_is_exception(env, res));
- assert(enif_has_pending_exception(env));
+ assert(enif_has_pending_exception(env, NULL));
if (strcmp(arg, "tuple") == 0) {
return enif_make_tuple2(env, argv[0], res);
} else {