|
181 | 181 | to dispatch the work to another thread, return |
182 | 182 | from the native function, and wait for the result. The thread can send |
183 | 183 | the result back to the calling thread using message passing. Information |
184 | | - about thread primitives can be found below.</p> |
| 184 | + about thread primitives can be found below. If you have built your system |
| 185 | + with <em>the currently experimental</em> support for dirty schedulers, |
| 186 | + you may want to try out this functionality by dispatching the work to a |
| 187 | + <seealso marker="#dirty_nifs">dirty NIF</seealso>, |
| 188 | + which does not have the same duration restriction as a normal NIF.</p> |
185 | 189 | </description> |
186 | 190 | <section> |
187 | 191 | <title>FUNCTIONALITY</title> |
|
312 | 316 | <p>The library initialization callbacks <c>load</c>, <c>reload</c> and |
313 | 317 | <c>upgrade</c> are all thread-safe even for shared state data.</p> |
314 | 318 | </item> |
| 319 | + <tag>Dirty NIFs</tag> |
| 320 | + <item><p><marker id="dirty_nifs"/><em>Note that the dirty NIF functionality |
| 321 | + is experimental</em> and that you have to enable support for dirty |
| 322 | + schedulers when building OTP in order to try the functionality out. Native functions |
| 323 | + <seealso marker="#lengthy_work"> |
| 324 | + must normally run quickly</seealso>, as explained earlier in this document. They |
| 325 | + generally should execute for no more than a millisecond. But not all native functions |
| 326 | + can execute so quickly; for example, functions that encrypt large blocks of data or |
| 327 | + perform lengthy file system operations can often run for tens of seconds or more.</p> |
| 328 | + <p>A NIF that cannot execute in a millisecond or less is called a "dirty NIF" since |
| 329 | + it performs work that the Erlang runtime cannot handle cleanly. Applications |
| 330 | + that make use of such functions must indicate to the runtime that the functions are |
| 331 | + dirty so they can be handled specially. To schedule a dirty NIF for execution, the |
| 332 | + application calls <seealso marker="#enif_schedule_dirty_nif">enif_schedule_dirty_nif</seealso>, |
| 333 | + passing to it a pointer to the dirty NIF to be executed and indicating with a flag |
| 334 | + argument whether it expects the operation to be CPU-bound or I/O-bound.</p> |
| 335 | + <p>All dirty NIFs must ultimately invoke the <seealso marker="#enif_schedule_dirty_nif_finalizer"> |
| 336 | + enif_schedule_dirty_nif_finalizer</seealso> as their final action, passing to it the |
| 337 | + result they wish to return to the original caller. A finalizer function can either |
| 338 | + receive the result and return it directly, or it can return a different value instead. |
| 339 | + For convenience, the NIF API provides the <seealso marker="#enif_dirty_nif_finalizer"> |
| 340 | + enif_dirty_nif_finalizer</seealso> function that applications can use as a finalizer; |
| 341 | + it simply returns its result argument.</p> |
| 342 | + <note><p>Dirty NIF support is available only when the emulator is configured with dirty |
| 343 | + schedulers enabled. This feature is currently disabled by default. To determine whether |
| 344 | + the dirty NIF API is available, native code can check to see if the C preprocessor macro |
| 345 | + <c>ERL_NIF_DIRTY_SCHEDULER_SUPPORT</c> is defined. Also, if the Erlang runtime was built |
| 346 | + without threading support, dirty schedulers are disabled. To check at runtime for the presence |
| 347 | + of dirty scheduler threads, code can call the <seealso marker="#enif_have_dirty_schedulers"><c> |
| 348 | + enif_have_dirty_schedulers()</c></seealso> API function, which returns true if dirty |
| 349 | + scheduler threads are present, false otherwise.</p></note> |
| 350 | + </item> |
315 | 351 | </taglist> |
316 | 352 | </section> |
317 | 353 | <section> |
@@ -610,6 +646,18 @@ typedef enum { |
610 | 646 | See also the <seealso marker="#WARNING">warning</seealso> text at the beginning of this document.</p> |
611 | 647 | </desc> |
612 | 648 | </func> |
| 649 | + <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_dirty_nif_finalizer(ErlNifEnv* env, ERL_NIF_TERM result)</nametext></name> |
| 650 | + <fsummary>Simple dirty NIF result finalizer</fsummary> |
| 651 | + <desc> |
| 652 | + <p>A convenience function that a dirty NIF can use as a finalizer that simply |
| 653 | + return its <c>result</c> argument as its return value. This function is provided |
| 654 | + for dirty NIFs with results that should be returned directly to the original caller.</p> |
| 655 | + <note><p>This function is available only when the emulator is configured with dirty |
| 656 | + schedulers enabled. This feature is currently disabled by default. To determine whether |
| 657 | + the dirty NIF API is available, native code can check to see if the C preprocessor macro |
| 658 | + <c>ERL_NIF_DIRTY_SCHEDULER_SUPPORT</c> is defined.</p></note> |
| 659 | + </desc> |
| 660 | + </func> |
613 | 661 | <func><name><ret>int</ret><nametext>enif_equal_tids(ErlNifTid tid1, ErlNifTid tid2)</nametext></name> |
614 | 662 | <fsummary></fsummary> |
615 | 663 | <desc><p>Same as <seealso marker="erl_driver#erl_drv_equal_tids">erl_drv_equal_tids</seealso>. |
@@ -730,6 +778,22 @@ typedef enum { |
730 | 778 | and return true, or return false if <c>term</c> is not an unsigned integer or is |
731 | 779 | outside the bounds of type <c>unsigned long</c>.</p></desc> |
732 | 780 | </func> |
| 781 | + <func><name><ret>int</ret><nametext>enif_have_dirty_schedulers()</nametext></name> |
| 782 | + <fsummary>Runtime check for the presence of dirty scheduler threads</fsummary> |
| 783 | + <desc> |
| 784 | + <p>Check at runtime for the presence of dirty scheduler threads. If the emulator is |
| 785 | + built with threading support, dirty scheduler threads are available and |
| 786 | + <c>enif_have_dirty_schedulers()</c> returns true. If the emulator was built without |
| 787 | + threading support, <c>enif_have_dirty_schedulers()</c> returns false.</p> |
| 788 | + <p>If dirty scheduler threads are not available in the emulator, calls to |
| 789 | + <c>enif_schedule_dirty_nif</c> and <c>enif_schedule_dirty_nif_finalizer</c> result in |
| 790 | + the NIF and finalizer functions being called directly within the calling thread.</p> |
| 791 | + <note><p>This function is available only when the emulator is configured with dirty |
| 792 | + schedulers enabled. This feature is currently disabled by default. To determine whether |
| 793 | + the dirty NIF API is available, native code can check to see if the C preprocessor macro |
| 794 | + <c>ERL_NIF_DIRTY_SCHEDULER_SUPPORT</c> is defined.</p></note> |
| 795 | + </desc> |
| 796 | + </func> |
733 | 797 | <func><name><ret>int</ret><nametext>enif_inspect_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term, ErlNifBinary* bin)</nametext></name> |
734 | 798 | <fsummary>Inspect the content of a binary</fsummary> |
735 | 799 | <desc><p>Initialize the structure pointed to by <c>bin</c> with |
@@ -777,6 +841,20 @@ typedef enum { |
777 | 841 | Erlang operators <c>=:=</c> and |
778 | 842 | <c>=/=</c>.</p></desc> |
779 | 843 | </func> |
| 844 | + <func><name><ret>int</ret><nametext>enif_is_on_dirty_scheduler(ErlNifEnv* env)</nametext></name> |
| 845 | + <fsummary>Check to see if executing on a dirty scheduler thread</fsummary> |
| 846 | + <desc> |
| 847 | + <p>Check to see if the current NIF is executing on a dirty scheduler thread. If the |
| 848 | + emulator is built with threading support, calling <c>enif_is_on_dirty_scheduler</c> |
| 849 | + from within a dirty NIF returns true. It returns false when the calling NIF is a regular |
| 850 | + NIF or a NIF finalizer, both of which run on normal scheduler threads, or when the emulator |
| 851 | + is built without threading support.</p> |
| 852 | + <note><p>This function is available only when the emulator is configured with dirty |
| 853 | + schedulers enabled. This feature is currently disabled by default. To determine whether |
| 854 | + the dirty NIF API is available, native code can check to see if the C preprocessor macro |
| 855 | + <c>ERL_NIF_DIRTY_SCHEDULER_SUPPORT</c> is defined.</p></note> |
| 856 | + </desc> |
| 857 | + </func> |
780 | 858 | <func><name><ret>int</ret><nametext>enif_is_pid(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> |
781 | 859 | <fsummary>Determine if a term is a pid</fsummary> |
782 | 860 | <desc><p>Return true if <c>term</c> is a pid.</p></desc> |
@@ -1141,6 +1219,48 @@ typedef enum { |
1141 | 1219 | <desc><p>Same as <seealso marker="erl_driver#erl_drv_rwlock_tryrwlock">erl_drv_rwlock_tryrwlock</seealso>. |
1142 | 1220 | </p></desc> |
1143 | 1221 | </func> |
| 1222 | + <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_schedule_dirty_nif(ErlNifEnv* env, int flags, ERL_NIF_TERM (*fp)(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]), int argc, const ERL_NIF_TERM argv[])</nametext></name> |
| 1223 | + <fsummary>Schedule a dirty NIF for execution</fsummary> |
| 1224 | + <desc> |
| 1225 | + <p>Schedule dirty NIF <c>fp</c> to execute a long-running operation. The <c>flags</c> |
| 1226 | + argument must be set to either <c>ERL_NIF_DIRTY_JOB_CPU_BOUND</c> if the job is expected to |
| 1227 | + be primarily CPU-bound, or <c>ERL_NIF_DIRTY_JOB_IO_BOUND</c> for jobs that will be |
| 1228 | + I/O-bound. The <c>argc</c> and <c>argv</c> arguments can either be the originals passed |
| 1229 | + into the calling NIF, or they can be values created by the calling NIF. The calling |
| 1230 | + NIF must use the return value of <c>enif_schedule_dirty_nif</c> as its own return value.</p> |
| 1231 | + <p>Be aware that <c>enif_schedule_dirty_nif</c>, as its name implies, only schedules the |
| 1232 | + dirty NIF for future execution. The calling NIF does not block waiting for the dirty NIF to |
| 1233 | + execute and return, which means that the calling NIF can't expect to receive the dirty NIF |
| 1234 | + return value and use it for further operations.</p> |
| 1235 | + <p>A dirty NIF may not invoke the <seealso marker="#enif_make_badarg">enif_make_badarg</seealso> |
| 1236 | + to raise an exception. If it wishes to return an exception, the dirty NIF should pass a |
| 1237 | + regular result indicating the exception details to its finalizer, and allow the finalizer |
| 1238 | + to raise the exception on its behalf.</p> |
| 1239 | + <note><p>This function is available only when the emulator is configured with dirty schedulers |
| 1240 | + enabled. This feature is currently disabled by default. To determine whether the dirty NIF API |
| 1241 | + is available, native code can check to see if the C preprocessor macro |
| 1242 | + <c>ERL_NIF_DIRTY_SCHEDULER_SUPPORT</c> is defined.</p></note> |
| 1243 | + </desc> |
| 1244 | + </func> |
| 1245 | + <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_schedule_dirty_nif_finalizer(ErlNifEnv* env, ERL_NIF_TERM result, ERL_NIF_TERM (*fp)(ErlNifEnv* env, ERL_NIF_TERM result))</nametext></name> |
| 1246 | + <fsummary>Schedule a dirty NIF finalizer</fsummary> |
| 1247 | + <desc> |
| 1248 | + <p>When a dirty NIF finishes executing, it must schedule a finalizer function to return |
| 1249 | + its result to the original NIF caller. The dirty NIF passes <c>result</c> as the value it |
| 1250 | + wants the finalizer to use as the return value. The <c>fp</c> argument is a pointer to the |
| 1251 | + finalizer function. The NIF API provides the <seealso marker="#enif_dirty_nif_finalizer"> |
| 1252 | + enif_dirty_nif_finalizer</seealso> function that can be used as a finalizer that simply |
| 1253 | + returns its <c>result</c> argument. You are also free to write your own custom finalizer |
| 1254 | + that uses <c>result</c> to derive a different return value, or ignores <c>result</c> |
| 1255 | + entirely and returns a completely different value.</p> |
| 1256 | + <p>Without exception, all dirty NIFs must invoke <c>enif_schedule_dirty_nif_finalizer</c> |
| 1257 | + to complete their execution.</p> |
| 1258 | + <note><p>This function is available only when the emulator is configured with dirty |
| 1259 | + schedulers enabled. This feature is currently disabled by default. To determine whether |
| 1260 | + the dirty NIF API is available, native code can check to see if the C preprocessor macro |
| 1261 | + <c>ERL_NIF_DIRTY_SCHEDULER_SUPPORT</c> is defined.</p></note> |
| 1262 | + </desc> |
| 1263 | + </func> |
1144 | 1264 | <func><name><ret>ErlNifPid *</ret><nametext>enif_self(ErlNifEnv* caller_env, ErlNifPid* pid)</nametext></name> |
1145 | 1265 | <fsummary>Get the pid of the calling process.</fsummary> |
1146 | 1266 | <desc><p>Initialize the pid variable <c>*pid</c> to represent the |
|
0 commit comments