1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 1996-2020. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20
21 #ifndef __GLOBAL_H__
22 #define __GLOBAL_H__
23
24 #include "sys.h"
25 #include <stddef.h> /* offsetof() */
26 #include "erl_alloc.h"
27 #include "erl_vm.h"
28 #include "erl_node_container_utils.h"
29 #include "hash.h"
30 #include "index.h"
31 #include "atom.h"
32 #include "code_ix.h"
33 #include "export.h"
34 #include "module.h"
35 #include "register.h"
36 #include "erl_fun.h"
37 #include "erl_node_tables.h"
38 #include "erl_process.h"
39 #include "erl_sys_driver.h"
40 #include "erl_debug.h"
41 #include "error.h"
42 #include "erl_utils.h"
43 #include "erl_port.h"
44 #include "erl_gc.h"
45 #include "erl_nif.h"
46 #define ERTS_BINARY_TYPES_ONLY__
47 #include "erl_binary.h"
48 #undef ERTS_BINARY_TYPES_ONLY__
49
50 struct enif_func_t;
51
52 #ifdef DEBUG
53 # define ERTS_NIF_ASSERT_IN_ENV
54 #endif
55 struct enif_environment_t /* ErlNifEnv */
56 {
57 struct erl_module_nif* mod_nif;
58 Process* proc;
59 Eterm* hp;
60 Eterm* hp_end;
61 ErlHeapFragment* heap_frag;
62 struct enif_tmp_obj_t* tmp_obj_list;
63 int exception_thrown; /* boolean */
64 Process *tracee;
65 int exiting; /* boolean (dirty nifs might return in exiting state) */
66
67 #ifdef ERTS_NIF_ASSERT_IN_ENV
68 int dbg_disable_assert_in_env;
69 #endif
70 };
71 struct enif_resource_type_t
72 {
73 struct enif_resource_type_t* next; /* list of all resource types */
74 struct enif_resource_type_t* prev;
75 struct erl_module_nif* owner; /* that created this type and thus implements the destructor*/
76 ErlNifResourceTypeInit fn;
77 ErlNifResourceTypeInit fn_real;
78 erts_refc_t refc; /* num of resources of this type (HOTSPOT warning)
79 +1 for active erl_module_nif */
80 Eterm module;
81 Eterm name;
82 };
83
84 typedef struct
85 {
86 erts_mtx_t lock;
87 ErtsMonitor* root;
88 Uint refc;
89 size_t user_data_sz;
90 } ErtsResourceMonitors;
91
92 typedef struct ErtsResource_
93 {
94 struct enif_resource_type_t* type;
95 ErtsResourceMonitors* monitors;
96 #ifdef DEBUG
97 erts_refc_t nif_refc;
98 #else
99 # ifdef ARCH_32
100 byte align__[4];
101 # endif
102 #endif
103 char data[1];
104 }ErtsResource;
105
106 #define DATA_TO_RESOURCE(PTR) ErtsContainerStruct(PTR, ErtsResource, data)
107 #define erts_resource_ref_size(P) ERTS_MAGIC_REF_THING_SIZE
108
109 extern Eterm erts_bld_resource_ref(Eterm** hp, ErlOffHeap*, ErtsResource*);
110
111 extern ErtsCodePtr erts_call_nif_early(Process* c_p, const ErtsCodeInfo* ci);
112 extern void erts_pre_nif(struct enif_environment_t*, Process*,
113 struct erl_module_nif*, Process* tracee);
114 extern void erts_post_nif(struct enif_environment_t* env);
115 #ifdef DEBUG
116 int erts_dbg_is_resource_dying(ErtsResource*);
117 #endif
118 extern void erts_resource_stop(ErtsResource*, ErlNifEvent, int is_direct_call);
119 void erts_fire_nif_monitor(ErtsMonitor *tmon);
120 void erts_nif_demonitored(ErtsResource* resource);
121 extern void erts_add_taint(Eterm mod_atom);
122 extern Eterm erts_nif_taints(Process* p);
123 extern void erts_print_nif_taints(fmtfn_t to, void* to_arg);
124
125 /* Loads the specified NIF. The caller must have code write permission. */
126 Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args);
127
128 void erts_unload_nif(struct erl_module_nif* nif);
129 extern void erl_nif_init(void);
130 extern int erts_nif_get_funcs(struct erl_module_nif*,
131 struct enif_func_t **funcs);
132 extern Module *erts_nif_get_module(struct erl_module_nif*);
133 extern Eterm erts_nif_call_function(Process *p, Process *tracee,
134 struct erl_module_nif*,
135 struct enif_func_t *,
136 int argc, Eterm *argv);
137
138 int erts_call_dirty_nif(ErtsSchedulerData *esdp, Process *c_p,
139 ErtsCodePtr I, Eterm *reg);
140 ErtsMessage* erts_create_message_from_nif_env(ErlNifEnv* msg_env);
141
142
143 /* Driver handle (wrapper for old plain handle) */
144 #define ERL_DE_OK 0
145 #define ERL_DE_UNLOAD 1
146 #define ERL_DE_FORCE_UNLOAD 2
147 #define ERL_DE_RELOAD 3
148 #define ERL_DE_FORCE_RELOAD 4
149 #define ERL_DE_PERMANENT 5
150
151 #define ERL_DE_PROC_LOADED 0
152 #define ERL_DE_PROC_AWAIT_UNLOAD 1
153 #define ERL_DE_PROC_AWAIT_UNLOAD_ONLY 2
154 #define ERL_DE_PROC_AWAIT_LOAD 3
155
156 /* Flags for process entries */
157 #define ERL_DE_FL_DEREFERENCED 1
158
159 /* Flags for drivers, put locking policy here /PaN */
160 #define ERL_DE_FL_KILL_PORTS 1
161
162 #define ERL_FL_CONSISTENT_MASK ( ERL_DE_FL_KILL_PORTS )
163
164 /* System specific load errors are returned as positive values */
165 #define ERL_DE_NO_ERROR 0
166 #define ERL_DE_LOAD_ERROR_NO_INIT -1
167 #define ERL_DE_LOAD_ERROR_FAILED_INIT -2
168 #define ERL_DE_LOAD_ERROR_BAD_NAME -3
169 #define ERL_DE_LOAD_ERROR_NAME_TO_LONG -4
170 #define ERL_DE_LOAD_ERROR_INCORRECT_VERSION -5
171 #define ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY -6
172 #define ERL_DE_ERROR_UNSPECIFIED -7
173 #define ERL_DE_LOOKUP_ERROR_NOT_FOUND -8
174 #define ERL_DE_DYNAMIC_ERROR_OFFSET -10
175
176 typedef struct de_proc_entry {
177 Process *proc; /* The process... */
178 Uint awaiting_status; /* PROC_LOADED == Have loaded the driver
179 PROC_AWAIT_UNLOAD == Wants to be notified
180 when we have unloaded the driver (was locked)
181 PROC_AWAIT_LOAD == Wants to be notified when we
182 reloaded the driver (old was locked) */
183 Uint flags; /* ERL_FL_DE_DEREFERENCED when reload in progress */
184 Eterm heap[ERTS_REF_THING_SIZE]; /* "ref heap" */
185 struct de_proc_entry *next;
186 } DE_ProcEntry;
187
188 typedef struct {
189 void *handle; /* Handle for DLL or SO (for dyn. drivers). */
190 DE_ProcEntry *procs; /* List of pids that have loaded this driver,
191 or that wait for it to change state */
192 erts_refc_t refc; /* Number of ports/processes having
193 references to the driver */
194 erts_atomic32_t port_count; /* Number of ports using the driver */
195 Uint flags; /* ERL_DE_FL_KILL_PORTS */
196 int status; /* ERL_DE_xxx */
197 char *full_path; /* Full path of the driver */
198 char *reload_full_path; /* If status == ERL_DE_RELOAD, this contains
199 full name of driver (path) */
200 char *reload_driver_name; /* ... and this contains the driver name */
201 Uint reload_flags; /* flags for reloaded driver */
202 } DE_Handle;
203
204 /*
205 * This structure represents a link to the next driver.
206 */
207
208 struct erts_driver_t_ {
209 erts_driver_t *next;
210 erts_driver_t *prev;
211 Eterm name_atom;
212 char *name;
213 struct {
214 int major;
215 int minor;
216 } version;
217 int flags;
218 DE_Handle *handle;
219 erts_mtx_t *lock;
220 ErlDrvEntry *entry;
221 ErlDrvData (*start)(ErlDrvPort port, char *command, SysDriverOpts* opts);
222 void (*stop)(ErlDrvData drv_data);
223 void (*finish)(void);
224 void (*flush)(ErlDrvData drv_data);
225 void (*output)(ErlDrvData drv_data, char *buf, ErlDrvSizeT len);
226 void (*outputv)(ErlDrvData drv_data, ErlIOVec *ev); /* Might be NULL */
227 ErlDrvSSizeT (*control)(ErlDrvData drv_data, unsigned int command,
228 char *buf, ErlDrvSizeT len,
229 char **rbuf, ErlDrvSizeT rlen); /* Might be NULL */
230 ErlDrvSSizeT (*call)(ErlDrvData drv_data, unsigned int command,
231 char *buf, ErlDrvSizeT len,
232 char **rbuf, ErlDrvSizeT rlen, /* Might be NULL */
233 unsigned int *flags);
234 void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event);
235 void (*ready_output)(ErlDrvData drv_data, ErlDrvEvent event);
236 void (*timeout)(ErlDrvData drv_data);
237 void (*ready_async)(ErlDrvData drv_data, ErlDrvThreadData thread_data); /* Might be NULL */
238 void (*process_exit)(ErlDrvData drv_data, ErlDrvMonitor *monitor);
239 void (*stop_select)(ErlDrvEvent event, void*); /* Might be NULL */
240 void (*emergency_close)(ErlDrvData drv_data); /* Might be NULL */
241 };
242
243 extern erts_driver_t *driver_list;
244 extern erts_rwmtx_t erts_driver_list_lock;
245
246 extern void erts_ddll_init(void);
247 extern void erts_ddll_lock_driver(DE_Handle *dh, char *name);
248
249 /* These are for bookkeeping */
250 extern void erts_ddll_increment_port_count(DE_Handle *dh);
251 extern void erts_ddll_decrement_port_count(DE_Handle *dh);
252
253 /* These makes things happen, drivers may be scheduled for unload etc */
254 extern void erts_ddll_reference_driver(DE_Handle *dh);
255 extern void erts_ddll_reference_referenced_driver(DE_Handle *dh);
256 extern void erts_ddll_dereference_driver(DE_Handle *dh);
257
258 extern char *erts_ddll_error(int code);
259 extern void erts_ddll_proc_dead(Process *p, ErtsProcLocks plocks);
260 extern int erts_ddll_driver_ok(DE_Handle *dh);
261 extern void erts_ddll_remove_monitor(Process *p,
262 Eterm ref,
263 ErtsProcLocks plocks);
264 extern Eterm erts_ddll_monitor_driver(Process *p,
265 Eterm description,
266 ErtsProcLocks plocks);
267
268 /*
269 * This structure represents one type of a binary in a process.
270 */
271
272 typedef struct proc_bin {
273 Eterm thing_word; /* Subtag REFC_BINARY_SUBTAG. */
274 Uint size; /* Binary size in bytes. */
275 struct erl_off_heap_header *next;
276 Binary *val; /* Pointer to Binary structure. */
277 byte *bytes; /* Pointer to the actual data bytes. */
278 Uint flags; /* Flag word. */
279 } ProcBin;
280
281 #define PB_IS_WRITABLE 1 /* Writable (only one reference to ProcBin) */
282 #define PB_ACTIVE_WRITER 2 /* There is an active writer */
283
284 /*
285 * ProcBin size in Eterm words.
286 */
287 #define PROC_BIN_SIZE (sizeof(ProcBin)/sizeof(Eterm))
288
289 union erl_off_heap_ptr {
290 struct erl_off_heap_header* hdr;
291 ProcBin *pb;
292 struct erl_fun_thing* fun;
293 struct external_thing_* ext;
294 ErtsMRefThing *mref;
295 Eterm* ep;
296 void* voidp;
297 };
298
299 /* controls warning mapping in error_logger */
300
301 extern Eterm node_cookie;
302
303 extern int erts_backtrace_depth;
304 extern erts_atomic32_t erts_max_gen_gcs;
305
306 extern int bif_reductions; /* reductions + fcalls (when doing call_bif) */
307 extern int stackdump_on_exit;
308
309 /*
310 * Here is an implementation of a lightweight stack.
311 *
312 * Use it like this:
313 *
314 * DECLARE_ESTACK(Stack) (At the start of a block)
315 * ...
316 * ESTACK_PUSH(Stack, Term)
317 * ...
318 * if (ESTACK_ISEMPTY(Stack)) {
319 * Stack is empty
320 * } else {
321 * Term = ESTACK_POP(Stack);
322 * Process popped Term here
323 * }
324 * ...
325 * DESTROY_ESTACK(Stack)
326 */
327
328 typedef struct ErtsEStack_ {
329 Eterm* start;
330 Eterm* sp;
331 Eterm* end;
332 Eterm* edefault;
333 ErtsAlcType_t alloc_type;
334 }ErtsEStack;
335
336 #define DEF_ESTACK_SIZE (16)
337
338 void erl_grow_estack(ErtsEStack*, Uint need);
339 #define ESTK_CONCAT(a,b) a##b
340 #define ESTK_DEF_STACK(s) ESTK_CONCAT(s,_default_estack)
341
342 #define ESTACK_DEFAULT_VALUE(estack_default_stack_array, alloc_type) \
343 (ErtsEStack) { \
344 estack_default_stack_array, /* start */ \
345 estack_default_stack_array, /* sp */ \
346 estack_default_stack_array + DEF_ESTACK_SIZE, /* end */ \
347 estack_default_stack_array, /* default */ \
348 alloc_type /* alloc_type */ \
349 }
350
351 #define DECLARE_ESTACK(s) \
352 Eterm ESTK_DEF_STACK(s)[DEF_ESTACK_SIZE]; \
353 ErtsEStack s = { \
354 ESTK_DEF_STACK(s), /* start */ \
355 ESTK_DEF_STACK(s), /* sp */ \
356 ESTK_DEF_STACK(s) + DEF_ESTACK_SIZE, /* end */ \
357 ESTK_DEF_STACK(s), /* default */ \
358 ERTS_ALC_T_ESTACK /* alloc_type */ \
359 }
360
361 #define ESTACK_CHANGE_ALLOCATOR(s,t) \
362 do { \
363 if ((s).start != ESTK_DEF_STACK(s)) { \
364 erts_exit(ERTS_ERROR_EXIT, "Internal error - trying to change allocator " \
365 "type of active estack\n"); \
366 } \
367 (s).alloc_type = (t); \
368 } while (0)
369
370 #define DESTROY_ESTACK(s) \
371 do { \
372 if ((s).start != ESTK_DEF_STACK(s)) { \
373 erts_free((s).alloc_type, (s).start); \
374 } \
375 } while(0)
376
377 #define DESTROY_ESTACK_EXPLICIT_DEFAULT_ARRAY(s, the_estack_default_array) \
378 do { \
379 if ((s).start != the_estack_default_array) { \
380 erts_free((s).alloc_type, (s).start); \
381 } \
382 } while(0)
383
384 /* Allocate an array on the heap and move the stack there if the
385 default array (that is allocated on the heap is used) */
386 #define ENSURE_ESTACK_HEAP_STACK_ARRAY(s, the_estack_default_array)\
387 do {\
388 if ((s).start == the_estack_default_array) {\
389 UWord _wsz = ESTACK_COUNT(s);\
390 Eterm *_prev_stack_array = s.start;\
391 (s).start = erts_alloc((s).alloc_type, \
392 DEF_ESTACK_SIZE * sizeof(Eterm));\
393 sys_memcpy((s).start, _prev_stack_array, _wsz*sizeof(Eterm));\
394 (s).sp = (s).start + _wsz;\
395 (s).end = (s).start + DEF_ESTACK_SIZE;\
396 (s).alloc_type = (s).alloc_type;\
397 }\
398 (s).edefault = NULL;\
399 } while (0)
400
401
402 /*
403 * Do not free the stack after this, it may have pointers into what
404 * was saved in 'dst'.
405 */
406 #define ESTACK_SAVE(s,dst)\
407 do {\
408 if ((s).start == ESTK_DEF_STACK(s)) {\
409 UWord _wsz = ESTACK_COUNT(s);\
410 (dst)->start = erts_alloc((s).alloc_type,\
411 DEF_ESTACK_SIZE * sizeof(Eterm));\
412 sys_memcpy((dst)->start, (s).start,_wsz*sizeof(Eterm));\
413 (dst)->sp = (dst)->start + _wsz;\
414 (dst)->end = (dst)->start + DEF_ESTACK_SIZE;\
415 (dst)->edefault = NULL;\
416 (dst)->alloc_type = (s).alloc_type;\
417 } else\
418 *(dst) = (s);\
419 } while (0)
420
421 #define DESTROY_SAVED_ESTACK(estack)\
422 do {\
423 if ((estack)->start) {\
424 erts_free((estack)->alloc_type, (estack)->start);\
425 (estack)->start = NULL;\
426 }\
427 } while(0)
428
429 #define CLEAR_SAVED_ESTACK(estack) ((void) ((estack)->start = NULL))
430
431 /*
432 * Use on empty stack, only the allocator can be changed before this.
433 * The src stack is reset to NULL.
434 */
435 #define ESTACK_RESTORE(s, src) \
436 do { \
437 ASSERT((s).start == ESTK_DEF_STACK(s)); \
438 (s) = *(src); /* struct copy */ \
439 (src)->start = NULL; \
440 ASSERT((s).sp >= (s).start); \
441 ASSERT((s).sp <= (s).end); \
442 } while (0)
443
444 #define ESTACK_IS_STATIC(s) ((s).start == ESTK_DEF_STACK(s))
445
446 #define ESTACK_PUSH(s, x) \
447 do { \
448 if ((s).sp == (s).end) { \
449 erl_grow_estack(&(s), 1); \
450 } \
451 *(s).sp++ = (x); \
452 } while(0)
453
454 #define ESTACK_PUSH2(s, x, y) \
455 do { \
456 if ((s).sp > (s).end - 2) { \
457 erl_grow_estack(&(s), 2); \
458 } \
459 *(s).sp++ = (x); \
460 *(s).sp++ = (y); \
461 } while(0)
462
463 #define ESTACK_PUSH3(s, x, y, z) \
464 do { \
465 if ((s).sp > (s).end - 3) { \
466 erl_grow_estack(&s, 3); \
467 } \
468 *(s).sp++ = (x); \
469 *(s).sp++ = (y); \
470 *(s).sp++ = (z); \
471 } while(0)
472
473 #define ESTACK_PUSH4(s, E1, E2, E3, E4) \
474 do { \
475 if ((s).sp > (s).end - 4) { \
476 erl_grow_estack(&s, 4); \
477 } \
478 *(s).sp++ = (E1); \
479 *(s).sp++ = (E2); \
480 *(s).sp++ = (E3); \
481 *(s).sp++ = (E4); \
482 } while(0)
483
484 #define ESTACK_RESERVE(s, push_cnt) \
485 do { \
486 if ((s).sp > (s).end - (push_cnt)) { \
487 erl_grow_estack(&(s), (push_cnt)); \
488 } \
489 } while(0)
490
491 /* Must be preceded by ESTACK_RESERVE */
492 #define ESTACK_FAST_PUSH(s, x) \
493 do { \
494 ASSERT((s).sp < (s).end); \
495 *s.sp++ = (x); \
496 } while(0)
497
498 #define ESTACK_COUNT(s) ((s).sp - (s).start)
499 #define ESTACK_ISEMPTY(s) ((s).sp == (s).start)
500 #define ESTACK_POP(s) (ASSERT(!ESTACK_ISEMPTY(s)),(*(--(s).sp)))
501
502
503 /*
504 * WSTACK: same as ESTACK but with UWord instead of Eterm
505 */
506
507 typedef struct ErtsWStack_ {
508 UWord* wstart;
509 UWord* wsp;
510 UWord* wend;
511 UWord* wdefault;
512 ErtsAlcType_t alloc_type;
513 }ErtsWStack;
514
515 #define DEF_WSTACK_SIZE (16)
516
517 void erl_grow_wstack(ErtsWStack*, Uint need);
518 #define WSTK_CONCAT(a,b) a##b
519 #define WSTK_DEF_STACK(s) WSTK_CONCAT(s,_default_wstack)
520
521 #define WSTACK_DEFAULT_VALUE(wstack_default_stack_array, alloc_type) \
522 (ErtsWStack) { \
523 wstack_default_stack_array, /* start */ \
524 wstack_default_stack_array, /* sp */ \
525 wstack_default_stack_array + DEF_ESTACK_SIZE, /* end */ \
526 wstack_default_stack_array, /* default */ \
527 alloc_type /* alloc_type */ \
528 }
529
530 #define WSTACK_DECLARE(s) \
531 UWord WSTK_DEF_STACK(s)[DEF_WSTACK_SIZE]; \
532 ErtsWStack s = { \
533 WSTK_DEF_STACK(s), /* wstart */ \
534 WSTK_DEF_STACK(s), /* wsp */ \
535 WSTK_DEF_STACK(s) + DEF_WSTACK_SIZE, /* wend */ \
536 WSTK_DEF_STACK(s), /* wdflt */ \
537 ERTS_ALC_T_ESTACK /* alloc_type */ \
538 }
539 #define DECLARE_WSTACK WSTACK_DECLARE
540
541 typedef struct ErtsDynamicWStack_ {
542 UWord default_stack[DEF_WSTACK_SIZE];
543 ErtsWStack ws;
544 }ErtsDynamicWStack;
545
546 #define WSTACK_INIT(dwsp, ALC_TYPE) \
547 do { \
548 (dwsp)->ws.wstart = (dwsp)->default_stack; \
549 (dwsp)->ws.wsp = (dwsp)->default_stack; \
550 (dwsp)->ws.wend = (dwsp)->default_stack + DEF_WSTACK_SIZE;\
551 (dwsp)->ws.wdefault = (dwsp)->default_stack; \
552 (dwsp)->ws.alloc_type = ALC_TYPE; \
553 } while (0)
554
555 #define WSTACK_CHANGE_ALLOCATOR(s,t) \
556 do { \
557 if (s.wstart != WSTK_DEF_STACK(s)) { \
558 erts_exit(ERTS_ERROR_EXIT, "Internal error - trying to change allocator " \
559 "type of active wstack\n"); \
560 } \
561 s.alloc_type = (t); \
562 } while (0)
563
564 #define WSTACK_DESTROY(s) \
565 do { \
566 if (s.wstart != s.wdefault) { \
567 erts_free(s.alloc_type, s.wstart); \
568 } \
569 } while(0)
570 #define DESTROY_WSTACK WSTACK_DESTROY
571
572 #define DESTROY_WSTACK_EXPLICIT_DEFAULT_ARRAY(s, the_wstack_default_array) \
573 do { \
574 if ((s).wstart != the_wstack_default_array) { \
575 erts_free((s).alloc_type, (s).wstart); \
576 } \
577 } while(0)
578
579 #define ENSURE_WSTACK_HEAP_STACK_ARRAY(s, the_wstack_default_array)\
580 do {\
581 if ((s).wstart == the_wstack_default_array) {\
582 UWord _wsz = WSTACK_COUNT(s);\
583 UWord *_prev_stack_array = s.wstart;\
584 (s).wstart = erts_alloc((s).alloc_type, \
585 DEF_WSTACK_SIZE * sizeof(UWord)); \
586 sys_memcpy((s).wstart, _prev_stack_array, _wsz*sizeof(UWord));\
587 (s).wsp = (s).wstart + _wsz;\
588 (s).wend = (s).wstart + DEF_WSTACK_SIZE;\
589 (s).alloc_type = (s).alloc_type;\
590 }\
591 (s).wdefault = NULL;\
592 } while (0)
593
594 #define WSTACK_DEBUG(s) \
595 do { \
596 fprintf(stderr, "wstack size = %ld\r\n", s.wsp - s.wstart); \
597 fprintf(stderr, "wstack wstart = %p\r\n", s.wstart); \
598 fprintf(stderr, "wstack wsp = %p\r\n", s.wsp); \
599 } while(0)
600
601 /*
602 * Do not free the stack after this, it may have pointers into what
603 * was saved in 'dst'.
604 */
605 #define WSTACK_SAVE(s,dst)\
606 do {\
607 if (s.wstart == WSTK_DEF_STACK(s)) {\
608 UWord _wsz = WSTACK_COUNT(s);\
609 (dst)->wstart = erts_alloc(s.alloc_type,\
610 DEF_WSTACK_SIZE * sizeof(UWord));\
611 sys_memcpy((dst)->wstart, s.wstart,_wsz*sizeof(UWord));\
612 (dst)->wsp = (dst)->wstart + _wsz;\
613 (dst)->wend = (dst)->wstart + DEF_WSTACK_SIZE;\
614 (dst)->wdefault = NULL;\
615 (dst)->alloc_type = s.alloc_type;\
616 } else\
617 *(dst) = s;\
618 } while (0)
619
620 #define DESTROY_SAVED_WSTACK(wstack)\
621 do {\
622 if ((wstack)->wstart) {\
623 erts_free((wstack)->alloc_type, (wstack)->wstart);\
624 (wstack)->wstart = NULL;\
625 }\
626 } while(0)
627
628 #define CLEAR_SAVED_WSTACK(wstack) ((void) ((wstack)->wstart = NULL))
629
630 /*
631 * Use on empty stack, only the allocator can be changed before this.
632 * The src stack is reset to NULL.
633 */
634 #define WSTACK_RESTORE(s, src) \
635 do { \
636 ASSERT(s.wstart == WSTK_DEF_STACK(s)); \
637 s = *(src); /* struct copy */ \
638 (src)->wstart = NULL; \
639 ASSERT(s.wsp >= s.wstart); \
640 ASSERT(s.wsp <= s.wend); \
641 } while (0)
642
643 #define WSTACK_IS_STATIC(s) (s.wstart == WSTK_DEF_STACK(s))
644
645 #define WSTACK_PUSH(s, x) \
646 do { \
647 if (s.wsp == s.wend) { \
648 erl_grow_wstack(&s, 1); \
649 } \
650 *s.wsp++ = (x); \
651 } while(0)
652
653 #define WSTACK_PUSH2(s, x, y) \
654 do { \
655 if (s.wsp > s.wend - 2) { \
656 erl_grow_wstack(&s, 2); \
657 } \
658 *s.wsp++ = (x); \
659 *s.wsp++ = (y); \
660 } while(0)
661
662 #define WSTACK_PUSH3(s, x, y, z) \
663 do { \
664 if (s.wsp > s.wend - 3) { \
665 erl_grow_wstack(&s, 3); \
666 } \
667 *s.wsp++ = (x); \
668 *s.wsp++ = (y); \
669 *s.wsp++ = (z); \
670 } while(0)
671
672 #define WSTACK_PUSH4(s, A1, A2, A3, A4) \
673 do { \
674 if (s.wsp > s.wend - 4) { \
675 erl_grow_wstack(&s, 4); \
676 } \
677 *s.wsp++ = (A1); \
678 *s.wsp++ = (A2); \
679 *s.wsp++ = (A3); \
680 *s.wsp++ = (A4); \
681 } while(0)
682
683 #define WSTACK_PUSH5(s, A1, A2, A3, A4, A5) \
684 do { \
685 if (s.wsp > s.wend - 5) { \
686 erl_grow_wstack(&s, 5); \
687 } \
688 *s.wsp++ = (A1); \
689 *s.wsp++ = (A2); \
690 *s.wsp++ = (A3); \
691 *s.wsp++ = (A4); \
692 *s.wsp++ = (A5); \
693 } while(0)
694
695 #define WSTACK_PUSH6(s, A1, A2, A3, A4, A5, A6) \
696 do { \
697 if (s.wsp > s.wend - 6) { \
698 erl_grow_wstack(&s, 6); \
699 } \
700 *s.wsp++ = (A1); \
701 *s.wsp++ = (A2); \
702 *s.wsp++ = (A3); \
703 *s.wsp++ = (A4); \
704 *s.wsp++ = (A5); \
705 *s.wsp++ = (A6); \
706 } while(0)
707
708 #define WSTACK_RESERVE(s, push_cnt) \
709 do { \
710 if (s.wsp > s.wend - (push_cnt)) { \
711 erl_grow_wstack(&s, (push_cnt)); \
712 } \
713 } while(0)
714
715 /* Must be preceded by WSTACK_RESERVE */
716 #define WSTACK_FAST_PUSH(s, x) \
717 do { \
718 ASSERT(s.wsp < s.wend); \
719 *s.wsp++ = (x); \
720 } while(0)
721
722 #define WSTACK_COUNT(s) (s.wsp - s.wstart)
723 #define WSTACK_ISEMPTY(s) (s.wsp == s.wstart)
724 #define WSTACK_POP(s) ((ASSERT(s.wsp > s.wstart)),*(--s.wsp))
725
726 #define WSTACK_ROLLBACK(s, count) (ASSERT(WSTACK_COUNT(s) >= (count)), \
727 s.wsp = s.wstart + (count))
728
729 /* PSTACK - Stack of any type.
730 * Usage:
731 * {
732 * #define PSTACK_TYPE MyType
733 * PSTACK_DECLARE(s,16);
734 * MyType *sp = PSTACK_PUSH(s);
735 *
736 * sp->x = ....
737 * sp->y = ....
738 * sp = PSTACK_PUSH(s);
739 * ...
740 * sp = PSTACK_POP(s);
741 * if (PSTACK_IS_EMPTY(s)) {
742 * // sp is invalid when stack is empty after pop
743 * }
744 *
745 * PSTACK_DESTROY(s);
746 * }
747 */
748
749
750 typedef struct ErtsPStack_ {
751 byte* pstart;
752 int offs; /* "stack pointer" as byte offset from pstart */
753 int size; /* allocated size in bytes */
754 ErtsAlcType_t alloc_type;
755 }ErtsPStack;
756
757 void erl_grow_pstack(ErtsPStack* s, void* default_pstack, unsigned need_bytes);
758 #define PSTK_CONCAT(a,b) a##b
759 #define PSTK_DEF_STACK(s) PSTK_CONCAT(s,_default_pstack)
760
761 #define PSTACK_DECLARE(s, DEF_PSTACK_SIZE) \
762 PSTACK_TYPE PSTK_DEF_STACK(s)[DEF_PSTACK_SIZE]; \
763 ErtsPStack s = { (byte*)PSTK_DEF_STACK(s), /* pstart */ \
764 -(int)sizeof(PSTACK_TYPE), /* offs */ \
765 DEF_PSTACK_SIZE*sizeof(PSTACK_TYPE), /* size */ \
766 ERTS_ALC_T_ESTACK /* alloc_type */ \
767 }
768
769 #define PSTACK_CHANGE_ALLOCATOR(s,t) \
770 do { \
771 if (s.pstart != (byte*)PSTK_DEF_STACK(s)) { \
772 erts_exit(ERTS_ERROR_EXIT, "Internal error - trying to change allocator " \
773 "type of active pstack\n"); \
774 } \
775 s.alloc_type = (t); \
776 } while (0)
777
778 #define PSTACK_DESTROY(s) \
779 do { \
780 if (s.pstart != (byte*)PSTK_DEF_STACK(s)) { \
781 erts_free(s.alloc_type, s.pstart); \
782 } \
783 } while(0)
784
785 #define PSTACK_IS_EMPTY(s) (s.offs < 0)
786
787 #define PSTACK_COUNT(s) ((s.offs + sizeof(PSTACK_TYPE)) / sizeof(PSTACK_TYPE))
788
789 #define PSTACK_TOP(s) (ASSERT(!PSTACK_IS_EMPTY(s)), \
790 (PSTACK_TYPE*)(s.pstart + s.offs))
791
792 #define PSTACK_PUSH(s) \
793 (s.offs += sizeof(PSTACK_TYPE), \
794 ((s.offs == s.size) ? erl_grow_pstack(&s, PSTK_DEF_STACK(s), \
795 sizeof(PSTACK_TYPE)) : (void)0), \
796 ((PSTACK_TYPE*) (s.pstart + s.offs)))
797
798 #define PSTACK_POP(s) ((s.offs -= sizeof(PSTACK_TYPE)), \
799 (PSTACK_TYPE*)(s.pstart + s.offs))
800
801 /*
802 * Do not free the stack after this, it may have pointers into what
803 * was saved in 'dst'.
804 */
805 #define PSTACK_SAVE(s,dst)\
806 do {\
807 if (s.pstart == (byte*)PSTK_DEF_STACK(s)) {\
808 UWord _pbytes = PSTACK_COUNT(s) * sizeof(PSTACK_TYPE);\
809 (dst)->pstart = erts_alloc(s.alloc_type,\
810 sizeof(PSTK_DEF_STACK(s)));\
811 sys_memcpy((dst)->pstart, s.pstart, _pbytes);\
812 (dst)->offs = s.offs;\
813 (dst)->size = s.size;\
814 (dst)->alloc_type = s.alloc_type;\
815 } else\
816 *(dst) = s;\
817 } while (0)
818
819 /*
820 * Use on empty stack, only the allocator can be changed before this.
821 * The src stack is reset to NULL.
822 */
823 #define PSTACK_RESTORE(s, src) \
824 do { \
825 ASSERT(s.pstart == (byte*)PSTK_DEF_STACK(s)); \
826 s = *(src); /* struct copy */ \
827 (src)->pstart = NULL; \
828 ASSERT(s.offs >= -(int)sizeof(PSTACK_TYPE)); \
829 ASSERT(s.offs < s.size); \
830 } while (0)
831
832 #define PSTACK_DESTROY_SAVED(pstack)\
833 do {\
834 if ((pstack)->pstart) {\
835 erts_free((pstack)->alloc_type, (pstack)->pstart);\
836 (pstack)->pstart = NULL;\
837 }\
838 } while(0)
839
840
841 /*
842 * An implementation of lightweight unbounded queues,
843 * using a circular dynamic array.
844 * It does not include support for change_allocator.
845 *
846 * Use it like this:
847 *
848 * DECLARE_EQUEUE(Queue) (At the start of a block)
849 * ...
850 * EQUEUE_PUT(Queue, Term)
851 * ...
852 * if (EQUEUE_ISEMPTY(Queue)) {
853 * Queue is empty
854 * } else {
855 * Term = EQUEUE_GET(Stack);
856 * Process popped Term here
857 * }
858 * ...
859 * DESTROY_EQUEUE(Queue)
860 */
861
862 typedef struct {
863 Eterm* start;
864 Eterm* front;
865 Eterm* back;
866 int possibly_empty;
867 Eterm* end;
868 ErtsAlcType_t alloc_type;
869 } ErtsEQueue;
870
871 #define DEF_EQUEUE_SIZE (16)
872
873 void erl_grow_equeue(ErtsEQueue*, Eterm* def_queue);
874 #define EQUE_CONCAT(a,b) a##b
875 #define EQUE_DEF_QUEUE(q) EQUE_CONCAT(q,_default_equeue)
876
877 #define DECLARE_EQUEUE(q) \
878 UWord EQUE_DEF_QUEUE(q)[DEF_EQUEUE_SIZE]; \
879 ErtsEQueue q = { \
880 EQUE_DEF_QUEUE(q), /* start */ \
881 EQUE_DEF_QUEUE(q), /* front */ \
882 EQUE_DEF_QUEUE(q), /* back */ \
883 1, /* possibly_empty */ \
884 EQUE_DEF_QUEUE(q) + DEF_EQUEUE_SIZE, /* end */ \
885 ERTS_ALC_T_ESTACK /* alloc_type */ \
886 }
887
888 #define DESTROY_EQUEUE(q) \
889 do { \
890 if (q.start != EQUE_DEF_QUEUE(q)) { \
891 erts_free(q.alloc_type, q.start); \
892 } \
893 } while(0)
894
895 #define EQUEUE_PUT_UNCHECKED(q, x) \
896 do { \
897 q.possibly_empty = 0; \
898 *(q.back) = (x); \
899 if (++(q.back) == q.end) { \
900 q.back = q.start; \
901 } \
902 } while(0)
903
904 #define EQUEUE_PUT(q, x) \
905 do { \
906 if (q.back == q.front && !q.possibly_empty) { \
907 erl_grow_equeue(&q, EQUE_DEF_QUEUE(q)); \
908 } \
909 EQUEUE_PUT_UNCHECKED(q, x); \
910 } while(0)
911
912 #define EQUEUE_ISEMPTY(q) (q.back == q.front && q.possibly_empty)
913
914 ERTS_GLB_INLINE Eterm erts_equeue_get(ErtsEQueue *q);
915
916 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
erts_equeue_get(ErtsEQueue * q)917 ERTS_GLB_INLINE Eterm erts_equeue_get(ErtsEQueue *q) {
918 Eterm x;
919 q->possibly_empty = 1;
920 x = *(q->front);
921 if (++(q->front) == q->end) {
922 q->front = q->start;
923 }
924 return x;
925 }
926 #endif
927 #define EQUEUE_GET(q) erts_equeue_get(&(q));
928
929 /* binary.c */
930
931 void erts_emasculate_writable_binary(ProcBin* pb);
932 Eterm erts_new_heap_binary(Process *p, byte *buf, int len, byte** datap);
933 Eterm erts_new_mso_binary(Process*, byte*, Uint);
934 Eterm new_binary(Process*, const byte*, Uint);
935 Eterm erts_heap_factory_new_binary(ErtsHeapFactory *hfact, byte *buf,
936 Uint len, Uint reserve_size);
937 Eterm erts_realloc_binary(Eterm bin, size_t size);
938 Eterm erts_build_proc_bin(ErlOffHeap*, Eterm*, Binary*);
939
940 /* erl_bif_info.c */
941
942 Eterm
943 erts_bld_port_info(Eterm **hpp,
944 ErlOffHeap *ohp,
945 Uint *szp,
946 Port *prt,
947 Eterm item);
948 Eterm erts_bld_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh, Eterm tail);
949
950
951 void erts_bif_info_init(void);
952
953 /* bif.c */
954
955 void erts_queue_monitor_message(Process *,
956 ErtsProcLocks*,
957 Eterm,
958 Eterm,
959 Eterm,
960 Eterm);
961 void erts_init_trap_export(Export* ep, Eterm m, Eterm f, Uint a,
962 Eterm (*bif)(Process*, Eterm*, ErtsCodePtr));
963 void erts_init_bif(void);
964 Eterm erl_send(Process *p, Eterm to, Eterm msg);
965 int erts_set_group_leader(Process *proc, Eterm new_gl);
966
967 /* erl_bif_guard.c */
968
969 void erts_init_bif_guard(void);
970 Eterm erts_trapping_length_1(Process* p, Eterm* args);
971
972 /* erl_bif_op.c */
973
974 Eterm erl_is_function(Process* p, Eterm arg1, Eterm arg2);
975
976 /* beam_bif_load.c */
977 Eterm erts_check_process_code(Process *c_p, Eterm module, int *redsp, int fcalls);
978 #define ERTS_CLA_SCAN_WORDS_PER_RED 512
979
980 int erts_check_copy_literals_gc_need(Process *c_p, int *redsp,
981 char *literals, Uint lit_bsize);
982 Eterm erts_copy_literals_gc(Process *c_p, int *redsp, int fcalls);
983
984 Uint32 erts_block_release_literal_area(void);
985 void erts_unblock_release_literal_area(Uint32);
986
987 void erts_debug_foreach_release_literal_area_off_heap(void (*func)(ErlOffHeap *, void *),
988 void *arg);
989
990 typedef struct ErtsLiteralArea_ {
991 struct erl_off_heap_header *off_heap;
992 Eterm *end;
993 Eterm start[1]; /* beginning of area */
994 } ErtsLiteralArea;
995
996 void erts_queue_release_literals(Process *c_p, ErtsLiteralArea* literals);
997
998 #define ERTS_LITERAL_AREA_ALLOC_SIZE(N) \
999 (sizeof(ErtsLiteralArea) + sizeof(Eterm)*((N) - 1))
1000 #define ERTS_LITERAL_AREA_SIZE(AP) \
1001 (ERTS_LITERAL_AREA_ALLOC_SIZE((AP)->end - (AP)->start))
1002
1003 extern erts_atomic_t erts_copy_literal_area__;
1004 #define ERTS_COPY_LITERAL_AREA() \
1005 ((ErtsLiteralArea *) erts_atomic_read_nob(&erts_copy_literal_area__))
1006 extern Process *erts_literal_area_collector;
1007
1008 extern Process *erts_code_purger;
1009
1010 /* beam_load.c */
1011 typedef struct {
1012 const ErtsCodeMFA* mfa; /* Pointer to: Mod, Name, Arity */
1013 Uint needed; /* Heap space needed for entire tuple */
1014 Uint32 loc; /* Location in source code */
1015 const Eterm* fname_ptr; /* Pointer to fname table */
1016 } FunctionInfo;
1017
1018 Binary* erts_alloc_loader_state(void);
1019
1020 /* Return the module name (a tagged atom) for the prepared code in the magic
1021 * binary, or NIL if the binary does not contain prepared code. */
1022 Eterm erts_module_for_prepared_code(Binary* magic);
1023
1024 /* Return a non-zero value if the prepared module has an on_load function,
1025 * or 0 if it does not. */
1026 Eterm erts_has_code_on_load(Binary* magic);
1027
1028 Eterm erts_prepare_loading(Binary* loader_state, Process *c_p,
1029 Eterm group_leader, Eterm* modp,
1030 byte* code, Uint size);
1031 Eterm erts_finish_loading(Binary* loader_state, Process* c_p,
1032 ErtsProcLocks c_p_locks, Eterm* modp);
1033 Eterm erts_preload_module(Process *c_p, ErtsProcLocks c_p_locks,
1034 Eterm group_leader, Eterm* mod, byte* code, Uint size);
1035 void init_load(void);
1036 const ErtsCodeMFA* erts_find_function_from_pc(ErtsCodePtr pc);
1037 Eterm* erts_build_mfa_item(FunctionInfo* fi, Eterm* hp,
1038 Eterm args, Eterm* mfa_p, Eterm loc_tail);
1039 void erts_set_current_function(FunctionInfo* fi, const ErtsCodeMFA* mfa);
1040 Eterm erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info);
1041
1042 /* beam_ranges.c */
1043 void erts_init_ranges(void);
1044 void erts_start_staging_ranges(int num_new);
1045 void erts_end_staging_ranges(int commit);
1046 void erts_update_ranges(const BeamCodeHeader* code, Uint size);
1047 void erts_remove_from_ranges(const BeamCodeHeader* code);
1048 UWord erts_ranges_sz(void);
1049 void erts_lookup_function_info(FunctionInfo* fi,
1050 ErtsCodePtr pc,
1051 int full_info);
1052 extern ErtsLiteralArea** erts_dump_lit_areas;
1053 extern Uint erts_dump_num_lit_areas;
1054
1055 /* break.c */
1056 void init_break_handler(void);
1057 void erts_set_ignore_break(void);
1058 void erts_replace_intr(void);
1059 void process_info(fmtfn_t, void *);
1060 void print_process_info(fmtfn_t, void *, Process*, ErtsProcLocks);
1061 void info(fmtfn_t, void *);
1062 void loaded(fmtfn_t, void *);
1063 void erts_print_base64(fmtfn_t to, void *to_arg, const byte* src, Uint size);
1064
1065 /* sighandler sys.c */
1066 int erts_set_signal(Eterm signal, Eterm type);
1067
1068 /* erl_arith.c */
1069 double erts_get_positive_zero_float(void);
1070
1071 /* config.c */
1072
1073 __decl_noreturn void __noreturn erts_exit_epilogue(void);
1074 __decl_noreturn void __noreturn erts_exit(int n, const char*, ...);
1075 __decl_noreturn void __noreturn erts_flush_async_exit(int n, char*, ...);
1076 void erl_error(const char*, va_list);
1077
1078 /* This controls whether sharing-preserving copy is used by Erlang */
1079
1080 #ifdef SHCOPY
1081 #define SHCOPY_SEND
1082 #define SHCOPY_SPAWN
1083 #endif
1084
1085 /* The persistent state while the sharing-preserving copier works */
1086
1087 typedef struct {
1088 Eterm queue_default[DEF_EQUEUE_SIZE];
1089 Eterm* queue_start;
1090 Eterm* queue_end;
1091 ErtsAlcType_t queue_alloc_type;
1092 UWord bitstore_default[DEF_WSTACK_SIZE];
1093 UWord* bitstore_start;
1094 #ifdef DEBUG
1095 UWord* bitstore_stop;
1096 #endif
1097 ErtsAlcType_t bitstore_alloc_type;
1098 Eterm shtable_default[DEF_ESTACK_SIZE];
1099 Eterm* shtable_start;
1100 ErtsAlcType_t shtable_alloc_type;
1101 Uint literal_size;
1102 Eterm *lit_purge_ptr;
1103 Uint lit_purge_sz;
1104 int copy_literals;
1105 } erts_shcopy_t;
1106
1107 #define INITIALIZE_SHCOPY(info) \
1108 do { \
1109 ErtsLiteralArea *larea__ = ERTS_COPY_LITERAL_AREA(); \
1110 info.queue_start = info.queue_default; \
1111 info.bitstore_start = info.bitstore_default; \
1112 info.shtable_start = info.shtable_default; \
1113 info.literal_size = 0; \
1114 info.copy_literals = 0; \
1115 if (larea__) { \
1116 info.lit_purge_ptr = &larea__->start[0]; \
1117 info.lit_purge_sz = larea__->end - info.lit_purge_ptr; \
1118 } \
1119 else { \
1120 info.lit_purge_ptr = NULL; \
1121 info.lit_purge_sz = 0; \
1122 } \
1123 } while(0)
1124
1125 #define DESTROY_SHCOPY(info) \
1126 do { \
1127 if (info.queue_start != info.queue_default) { \
1128 erts_free(info.queue_alloc_type, info.queue_start); \
1129 } \
1130 if (info.bitstore_start != info.bitstore_default) { \
1131 erts_free(info.bitstore_alloc_type, info.bitstore_start); \
1132 } \
1133 if (info.shtable_start != info.shtable_default) { \
1134 erts_free(info.shtable_alloc_type, info.shtable_start); \
1135 } \
1136 } while(0)
1137
1138 /* copy.c */
1139 typedef struct {
1140 Eterm *lit_purge_ptr;
1141 Uint lit_purge_sz;
1142 } erts_literal_area_t;
1143
1144 #define INITIALIZE_LITERAL_PURGE_AREA(Area) \
1145 do { \
1146 ErtsLiteralArea *larea__ = ERTS_COPY_LITERAL_AREA(); \
1147 if (larea__) { \
1148 (Area).lit_purge_ptr = &larea__->start[0]; \
1149 (Area).lit_purge_sz = larea__->end - (Area).lit_purge_ptr; \
1150 } \
1151 else { \
1152 (Area).lit_purge_ptr = NULL; \
1153 (Area).lit_purge_sz = 0; \
1154 } \
1155 } while(0)
1156
1157 Eterm copy_object_x(Eterm, Process*, Uint);
1158 #define copy_object(Term, Proc) copy_object_x(Term,Proc,0)
1159
1160 Uint size_object_x(Eterm, erts_literal_area_t*);
1161 #define size_object(Term) size_object_x(Term,NULL)
1162 #define size_object_litopt(Term,LitArea) size_object_x(Term,LitArea)
1163
1164 Uint copy_shared_calculate(Eterm, erts_shcopy_t*);
1165 Uint size_shared(Eterm);
1166
1167 /* #define ERTS_COPY_REGISTER_LOCATION */
1168
1169 #ifdef ERTS_COPY_REGISTER_LOCATION
1170
1171 #define copy_shared_perform(U, V, X, Y, Z) \
1172 copy_shared_perform_x((U), (V), (X), (Y), (Z), __FILE__, __LINE__)
1173 Eterm copy_shared_perform_x(Eterm, Uint, erts_shcopy_t*, Eterm**, ErlOffHeap*,
1174 char *file, int line);
1175
1176 Eterm copy_struct_x(Eterm, Uint, Eterm**, ErlOffHeap*, Uint*, erts_literal_area_t*,
1177 char *file, int line);
1178 #define copy_struct(Obj,Sz,HPP,OH) \
1179 copy_struct_x(Obj,Sz,HPP,OH,NULL,NULL,__FILE__,__LINE__)
1180 #define copy_struct_litopt(Obj,Sz,HPP,OH,LitArea) \
1181 copy_struct_x(Obj,Sz,HPP,OH,NULL,LitArea,__FILE__,__LINE__)
1182
1183 #define copy_shallow(R, SZ, HPP, OH) \
1184 copy_shallow_x((R), (SZ), (HPP), (OH), __FILE__, __LINE__)
1185 Eterm copy_shallow_x(Eterm* ERTS_RESTRICT, Uint, Eterm**, ErlOffHeap*,
1186 char *file, int line);
1187
1188 #else
1189
1190 #define copy_shared_perform(U, V, X, Y, Z) \
1191 copy_shared_perform_x((U), (V), (X), (Y), (Z))
1192 Eterm copy_shared_perform_x(Eterm, Uint, erts_shcopy_t*, Eterm**, ErlOffHeap*);
1193
1194 Eterm copy_struct_x(Eterm, Uint, Eterm**, ErlOffHeap*, Uint*, erts_literal_area_t*);
1195 #define copy_struct(Obj,Sz,HPP,OH) \
1196 copy_struct_x(Obj,Sz,HPP,OH,NULL,NULL)
1197 #define copy_struct_litopt(Obj,Sz,HPP,OH,LitArea) \
1198 copy_struct_x(Obj,Sz,HPP,OH,NULL,LitArea)
1199
1200 #define copy_shallow(R, SZ, HPP, OH) \
1201 copy_shallow_x((R), (SZ), (HPP), (OH))
1202 Eterm copy_shallow_x(Eterm* ERTS_RESTRICT, Uint, Eterm**, ErlOffHeap*);
1203
1204 #endif
1205
1206 void erts_move_multi_frags(Eterm** hpp, ErlOffHeap*, ErlHeapFragment* first,
1207 Eterm* refs, unsigned nrefs, int literals);
1208
1209 /* Utilities */
1210 void erts_monitor_nodes_delete(ErtsMonitor *);
1211 extern Eterm erts_monitor_nodes(Process *, Eterm, Eterm);
1212 extern Eterm erts_processes_monitoring_nodes(Process *);
1213 extern int erts_do_net_exits(DistEntry*, Eterm);
1214 extern int distribution_info(fmtfn_t, void *);
1215 extern int is_node_name_atom(Eterm a);
1216
1217 extern int erts_net_message(Port *, DistEntry *, Uint32 conn_id,
1218 byte *, ErlDrvSizeT, Binary *, byte *, ErlDrvSizeT);
1219
1220 int erts_dist_pend_spawn_exit_delete(ErtsMonitor *mon);
1221 int erts_dist_pend_spawn_exit_parent_setup(ErtsMonitor *mon);
1222 int erts_dist_pend_spawn_exit_parent_wait(Process *c_p,
1223 ErtsProcLocks locks,
1224 ErtsMonitor *mon);
1225
1226 extern void init_dist(void);
1227 extern int stop_dist(void);
1228
1229 void erl_progressf(char* format, ...);
1230
1231 #ifdef MESS_DEBUG
1232 void print_pass_through(int, byte*, int);
1233 #endif
1234
1235 /* beam_emu.c */
1236 int catchlevel(Process*);
1237 void init_emulator(void);
1238 void process_main(ErtsSchedulerData *);
1239 void erts_dirty_process_main(ErtsSchedulerData *);
1240 Eterm build_stacktrace(Process* c_p, Eterm exc);
1241 Eterm expand_error_value(Process* c_p, Uint freason, Eterm Value);
1242 void erts_save_stacktrace(Process* p, struct StackTrace* s, int depth);
1243 ErtsCodePtr erts_printable_return_address(Process* p, Eterm *E) ERTS_NOINLINE;
1244
1245 /* erl_init.c */
1246
1247 typedef struct {
1248 Eterm delay_time;
1249 int context_reds;
1250 } ErtsModifiedTimings;
1251
1252 extern Export *erts_delay_trap;
1253 extern int erts_modified_timing_level;
1254 extern ErtsModifiedTimings erts_modified_timings[];
1255 #define ERTS_USE_MODIFIED_TIMING() \
1256 (erts_modified_timing_level >= 0)
1257 #define ERTS_MODIFIED_TIMING_DELAY \
1258 (erts_modified_timings[erts_modified_timing_level].delay_time)
1259 #define ERTS_MODIFIED_TIMING_CONTEXT_REDS \
1260 (erts_modified_timings[erts_modified_timing_level].context_reds)
1261 #define ERTS_MODIFIED_TIMING_INPUT_REDS \
1262 (erts_modified_timings[erts_modified_timing_level].input_reds)
1263
1264 extern int erts_no_line_info;
1265 extern Eterm erts_error_logger_warnings;
1266 extern int erts_initialized;
1267 extern int erts_compat_rel;
1268
1269 #ifdef BEAMASM
1270 extern int erts_jit_asm_dump;
1271 #endif
1272
1273 void erl_start(int, char**);
1274 void erts_usage(void);
1275 Eterm erts_preloaded(Process* p);
1276
1277
1278 /* erl_md5.c */
1279
1280 typedef struct {
1281 Uint32 state[4]; /* state (ABCD) */
1282 Uint32 count[2]; /* number of bits, modulo 2^64 (lsb first) */
1283 unsigned char buffer[64]; /* input buffer */
1284 } MD5_CTX;
1285
1286 void MD5Init(MD5_CTX *);
1287 void MD5Update(MD5_CTX *, unsigned char *, unsigned int);
1288 void MD5Final(unsigned char [16], MD5_CTX *);
1289
1290
1291 /* io.c */
1292
1293 typedef struct {
1294 char *name;
1295 char *driver_name;
1296 } ErtsPortNames;
1297
1298 #define ERTS_SPAWN_DRIVER 1
1299 #define ERTS_SPAWN_EXECUTABLE 2
1300 #define ERTS_SPAWN_ANY (ERTS_SPAWN_DRIVER | ERTS_SPAWN_EXECUTABLE)
1301 int erts_add_driver_entry(ErlDrvEntry *drv, DE_Handle *handle, int driver_list_locked, int taint);
1302 void erts_destroy_driver(erts_driver_t *drv);
1303 int erts_save_suspend_process_on_port(Port*, Process*);
1304 Port *erts_open_driver(erts_driver_t*, Eterm, char*, SysDriverOpts*, int *, int *);
1305 void erts_init_io(int, int, int);
1306 void erts_raw_port_command(Port*, byte*, Uint);
1307 void driver_report_exit(ErlDrvPort, int);
1308 LineBuf* allocate_linebuf(int);
1309 int async_ready(Port *, void*);
1310 ErtsPortNames *erts_get_port_names(Eterm, ErlDrvPort);
1311 void erts_free_port_names(ErtsPortNames *);
1312 Uint erts_port_ioq_size(Port *pp);
1313 void erts_stale_drv_select(Eterm, ErlDrvPort, ErlDrvEvent, int, int);
1314
1315 Port *erts_get_heart_port(void);
1316 void erts_emergency_close_ports(void);
1317 void erts_ref_to_driver_monitor(Eterm ref, ErlDrvMonitor *mon);
1318 Eterm erts_driver_monitor_to_ref(Eterm* hp, const ErlDrvMonitor *mon);
1319
1320 #if defined(ERTS_ENABLE_LOCK_COUNT)
1321 void erts_lcnt_update_driver_locks(int enable);
1322 void erts_lcnt_update_port_locks(int enable);
1323 #endif
1324
1325 /* driver_tab.c */
1326 typedef struct {
1327 ErlDrvEntry* de;
1328 int taint;
1329 } ErtsStaticDriver;
1330 typedef void *(*ErtsStaticNifInitFPtr)(void);
1331 typedef struct ErtsStaticNifEntry_ {
1332 const char *nif_name;
1333 ErtsStaticNifInitFPtr nif_init;
1334 int taint;
1335 } ErtsStaticNifEntry;
1336 ErtsStaticNifEntry* erts_static_nif_get_nif_init(const char *name, int len);
1337 int erts_is_static_nif(void *handle);
1338 void erts_init_static_drivers(void);
1339
1340 /* erl_drv_thread.c */
1341 void erl_drv_thr_init(void);
1342
1343 /* utils.c */
1344 void erts_cleanup_offheap(ErlOffHeap *offheap);
1345
1346 Uint64 erts_timestamp_millis(void);
1347
1348 Export* erts_find_function(Eterm, Eterm, unsigned int, ErtsCodeIndex);
1349
1350 /* ERTS_NOINLINE prevents link-time optimization across modules */
1351 const void *erts_get_stacklimit(void);
1352 int erts_check_below_limit(char *ptr, char *limit) ERTS_NOINLINE;
1353 int erts_check_above_limit(char *ptr, char *limit) ERTS_NOINLINE;
1354
1355 void *erts_ptr_id(void *ptr) ERTS_NOINLINE;
1356 int erts_check_if_stack_grows_downwards(char *ptr) ERTS_NOINLINE;
1357
1358 Eterm store_external_or_ref_in_proc_(Process *, Eterm);
1359 Eterm store_external_or_ref_(Uint **, ErlOffHeap*, Eterm);
1360
1361 typedef Eterm (*erts_ycf_continue_fun_t)(long* ycf_number_of_reduction_param,
1362 void** ycf_trap_state,
1363 void* ycf_extra_context);
1364 typedef void (*erts_ycf_destroy_trap_state_fun_t)(void *trap_state);
1365 typedef Eterm (*erts_ycf_yielding_fun_t)(long* ycf_nr_of_reductions_param,
1366 void** ycf_trap_state,
1367 void* ycf_extra_context,
1368 void* (*ycf_yield_alloc_fun) (size_t,void*),
1369 void (*ycf_yield_free_fun) (void*,void*),
1370 void* ycf_yield_alloc_free_context,
1371 size_t ycf_stack_alloc_size_or_max_size,
1372 void* ycf_stack_alloc_data,
1373 Process* p,
1374 Eterm* bif_args);
1375 Eterm erts_ycf_trap_driver(Process* p,
1376 Eterm* bif_args,
1377 int nr_of_arguments,
1378 int iterations_per_red,
1379 ErtsAlcType_t memory_allocation_type,
1380 size_t ycf_stack_alloc_size,
1381 int export_entry_index,
1382 erts_ycf_continue_fun_t ycf_continue_fun,
1383 erts_ycf_destroy_trap_state_fun_t ycf_destroy_fun,
1384 erts_ycf_yielding_fun_t ycf_yielding_fun);
1385
1386 /* A quick sort function that is compatible with the qsort function
1387 declared in stdlib.h. We need our own so that we can yield inside
1388 the function */
1389 typedef int (*erts_void_ptr_cmp_t)(const void *, const void *);
1390 void erts_qsort(void *base,
1391 size_t nr_of_items,
1392 size_t item_size,
1393 erts_void_ptr_cmp_t compare);
1394 /* YCF generated functions for yielding of erts_qsort. This means that
1395 the following three functions can be used when one needs a yieldable
1396 sorting function. See
1397 $ERL_TOP/erts/emulator/internal_doc/AutomaticYieldingOfCCode.md for
1398 information about using YCF generated functions.
1399
1400
1401 !!!!
1402 Note that the erts_qsort_swap that is used by erts_qsort does
1403 not have yielding enabled. If the array items are large erts_qsort
1404 should also trap in the erts_qsort_swap function, but this causes
1405 terrible performance when the array items are small, so one should
1406 investigate a fast-path approach
1407 */
1408 void erts_qsort_ycf_gen_destroy(void* ycf_my_trap_state);
1409 void erts_qsort_ycf_gen_continue(long* ycf_number_of_reduction_param,
1410 void** ycf_trap_state,
1411 void* ycf_extra_context /* Not used, can be NULL */);
1412 void erts_qsort_ycf_gen_yielding(long* ycf_nr_of_reductions_param,
1413 void** ycf_trap_state,
1414 void* ycf_extra_context, /* Not used, can be NULL */
1415 void* (*ycf_yield_alloc_fun) (size_t,void*),
1416 void (*ycf_yield_free_fun) (void*,void*),
1417 void* ycf_yield_alloc_free_context,
1418 size_t ycf_stack_alloc_size_or_max_size, /* Not used, can be 0 */
1419 void* ycf_stack_alloc_data, /* Not used, can be NULL */
1420 void *base,
1421 size_t nr_of_items,
1422 size_t item_size,
1423 erts_void_ptr_cmp_t compare);
1424 #if defined(DEBUG)
1425 /*
1426 * ycf_debug_get_stack_start is used in YCF's debug mode (see
1427 * documentation for the -debug flag of the YCF tool). The function
1428 * ycf_debug_set_stack_start sets the value that the function
1429 * ycf_debug_get_stack_start returns for the current thread. The
1430 * function ycf_debug_reset_stack_start sets the value that the
1431 * function ycf_debug_get_stack_start returns to NULL for the current
1432 * thread.
1433 */
1434 void ycf_debug_set_stack_start(void * start);
1435 void ycf_debug_reset_stack_start(void);
1436 void *ycf_debug_get_stack_start(void);
1437 #endif
1438
1439 #define NC_HEAP_SIZE(NC) \
1440 (ASSERT(is_node_container((NC))), \
1441 IS_CONST((NC)) ? 0 : (thing_arityval(*boxed_val((NC))) + 1))
1442 #define STORE_NC(Hpp, ETpp, NC) \
1443 (ASSERT(is_node_container((NC))), \
1444 IS_CONST((NC)) ? (NC) : store_external_or_ref_((Hpp), (ETpp), (NC)))
1445 #define STORE_NC_IN_PROC(Pp, NC) \
1446 (ASSERT(is_node_container((NC))), \
1447 IS_CONST((NC)) ? (NC) : store_external_or_ref_in_proc_((Pp), (NC)))
1448
1449 /* duplicates from big.h */
1450 int term_to_Uint(Eterm term, Uint *up);
1451 int term_to_UWord(Eterm, UWord*);
1452
1453 #ifdef HAVE_ERTS_NOW_CPU
1454 extern int erts_cpu_timestamp;
1455 #endif
1456 /* erl_bif_chksum.c */
1457 void erts_init_bif_chksum(void);
1458 /* erl_bif_re.c */
1459 void erts_init_bif_re(void);
1460 Sint erts_re_set_loop_limit(Sint limit);
1461 /* erl_bif_binary.c */
1462 void erts_init_bif_binary(void);
1463 Sint erts_binary_set_loop_limit(Sint limit);
1464
1465 /* erl_bif_persistent.c */
1466 void erts_init_bif_persistent_term(void);
1467 void erts_init_persistent_dumping(void);
1468 extern ErtsLiteralArea** erts_persistent_areas;
1469 extern Uint erts_num_persistent_areas;
1470 void erts_debug_foreach_persistent_term_off_heap(void (*func)(ErlOffHeap *, void *),
1471 void *arg);
1472 int erts_debug_have_accessed_literal_area(ErtsLiteralArea *lap);
1473 void erts_debug_save_accessed_literal_area(ErtsLiteralArea *lap);
1474 Eterm erts_debug_persistent_term_xtra_info(Process* c_p);
1475
1476 /* external.c */
1477 void erts_init_external(void);
1478
1479 /* erl_map.c */
1480 void erts_init_map(void);
1481
1482 /* beam_debug.c */
1483 UWord erts_check_stack_recursion_downwards(char *start_c, char *prev_c);
1484 UWord erts_check_stack_recursion_upwards(char *start_c, char *prev_c);
1485 int erts_is_above_stack_limit(char *ptr);
1486
1487 /* erl_unicode.c */
1488 void erts_init_unicode(void);
1489 Sint erts_unicode_set_loop_limit(Sint limit);
1490
1491 void erts_native_filename_put(Eterm ioterm, int encoding, byte *p) ;
1492 Sint erts_native_filename_need(Eterm ioterm, int encoding);
1493 void erts_copy_utf8_to_utf16_little(byte *target, byte *bytes, int num_chars);
1494 int erts_analyze_utf8(byte *source, Uint size,
1495 byte **err_pos, Uint *num_chars, int *left);
1496 int erts_analyze_utf8_x(byte *source, Uint size,
1497 byte **err_pos, Uint *num_chars, int *left,
1498 Sint *num_latin1_chars, Uint max_chars);
1499 char *erts_convert_filename_to_native(Eterm name, char *statbuf,
1500 size_t statbuf_size,
1501 ErtsAlcType_t alloc_type,
1502 int allow_empty, int allow_atom,
1503 Sint *used /* out */);
1504 char *erts_convert_filename_to_encoding(Eterm name, char *statbuf,
1505 size_t statbuf_size,
1506 ErtsAlcType_t alloc_type,
1507 int allow_empty, int allow_atom,
1508 int encoding,
1509 Sint *used /* out */,
1510 Uint extra);
1511 char* erts_convert_filename_to_wchar(byte* bytes, Uint size,
1512 char *statbuf, size_t statbuf_size,
1513 ErtsAlcType_t alloc_type, Sint* used,
1514 Uint extra_wchars);
1515 Eterm erts_convert_native_to_filename(Process *p, size_t size, byte *bytes);
1516 Eterm erts_utf8_to_list(Process *p, Uint num, byte *bytes, Uint sz, Uint left,
1517 Uint *num_built, Uint *num_eaten, Eterm tail);
1518 int erts_utf8_to_latin1(byte* dest, const byte* source, int slen);
1519 #define ERTS_UTF8_OK 0
1520 #define ERTS_UTF8_INCOMPLETE 1
1521 #define ERTS_UTF8_ERROR 2
1522 #define ERTS_UTF8_ANALYZE_MORE 3
1523 #define ERTS_UTF8_OK_MAX_CHARS 4
1524
1525 void bin_write(fmtfn_t, void*, byte*, size_t);
1526 Sint intlist_to_buf(Eterm, char*, Sint); /* most callers pass plain char*'s */
1527 int erts_unicode_list_to_buf(Eterm list, byte *buf, Sint len, Sint* written);
1528 Sint erts_unicode_list_to_buf_len(Eterm list);
1529
1530 int Sint_to_buf(Sint num, int base, char **buf_p, size_t buf_size);
1531
1532 #define ERTS_IOLIST_STATE_INITER(C_P, OBJ) \
1533 {(C_P), 0, 0, (OBJ), {NULL, NULL, NULL, ERTS_ALC_T_INVALID}, 0, 0}
1534
1535 #define ERTS_IOLIST_STATE_MOVE(TO, FROM) \
1536 sys_memcpy((void *) (TO), (void *) (FROM), sizeof(ErtsIOListState))
1537
1538 #define ERTS_IOLIST_SIZE_YIELDS_COUNT_PER_RED 8
1539
1540 typedef struct {
1541 Process *c_p;
1542 ErlDrvSizeT size;
1543 Uint offs;
1544 Eterm obj;
1545 ErtsEStack estack;
1546 int reds_left;
1547 int have_size;
1548 } ErtsIOListState;
1549
1550 #define ERTS_IOLIST2BUF_STATE_INITER(C_P, OBJ) \
1551 {ERTS_IOLIST_STATE_INITER((C_P), (OBJ)), {NULL, 0, 0, 0}, NULL, 0, NULL, 0}
1552
1553 #define ERTS_IOLIST2BUF_STATE_MOVE(TO, FROM) \
1554 sys_memcpy((void *) (TO), (void *) (FROM), sizeof(ErtsIOList2BufState))
1555
1556 #define ERTS_IOLIST_TO_BUF_BYTES_PER_YIELD_COUNT 32
1557 #define ERTS_IOLIST_TO_BUF_YIELD_COUNT_PER_RED 8
1558 #define ERTS_IOLIST_TO_BUF_BYTES_PER_RED \
1559 (ERTS_IOLIST_TO_BUF_YIELD_COUNT_PER_RED*ERTS_IOLIST_TO_BUF_BYTES_PER_YIELD_COUNT)
1560
1561 typedef struct {
1562 ErtsIOListState iolist;
1563 struct {
1564 byte *bptr;
1565 size_t size;
1566 Uint bitoffs;
1567 Uint bitsize;
1568 } bcopy;
1569 char *buf;
1570 ErlDrvSizeT len;
1571 Eterm *objp;
1572 int offset;
1573 } ErtsIOList2BufState;
1574
1575 #define ERTS_IOLIST_OK 0
1576 #define ERTS_IOLIST_OVERFLOW 1
1577 #define ERTS_IOLIST_TYPE 2
1578 #define ERTS_IOLIST_YIELD 3
1579
1580 Eterm buf_to_intlist(Eterm**, const char*, size_t, Eterm); /* most callers pass plain char*'s */
1581
1582 #define ERTS_IOLIST_TO_BUF_OVERFLOW (~((ErlDrvSizeT) 0))
1583 #define ERTS_IOLIST_TO_BUF_TYPE_ERROR (~((ErlDrvSizeT) 1))
1584 #define ERTS_IOLIST_TO_BUF_YIELD (~((ErlDrvSizeT) 2))
1585 #define ERTS_IOLIST_TO_BUF_FAILED(R) \
1586 (((R) & (~((ErlDrvSizeT) 3))) == (~((ErlDrvSizeT) 3)))
1587 #define ERTS_IOLIST_TO_BUF_SUCCEEDED(R) \
1588 (!ERTS_IOLIST_TO_BUF_FAILED((R)))
1589
1590 ErlDrvSizeT erts_iolist_to_buf(Eterm, char*, ErlDrvSizeT);
1591 ErlDrvSizeT erts_iolist_to_buf_yielding(ErtsIOList2BufState *);
1592 int erts_iolist_size_yielding(ErtsIOListState *state);
1593 int erts_iolist_size(Eterm, ErlDrvSizeT *);
1594 Sint is_string(Eterm);
1595 void erl_at_exit(void (*) (void*), void*);
1596 Eterm collect_memory(Process *);
1597 void dump_memory_to_fd(int);
1598 int dump_memory_data(const char *);
1599
1600 Eterm erts_unary_minus(Process* p, Eterm arg1);
1601 Eterm erts_mixed_plus(Process* p, Eterm arg1, Eterm arg2);
1602 Eterm erts_mixed_minus(Process* p, Eterm arg1, Eterm arg2);
1603 Eterm erts_mixed_times(Process* p, Eterm arg1, Eterm arg2);
1604 Eterm erts_mixed_div(Process* p, Eterm arg1, Eterm arg2);
1605
1606 int erts_int_div_rem(Process* p, Eterm arg1, Eterm arg2, Eterm *q, Eterm *r);
1607 Eterm erts_int_div(Process* p, Eterm arg1, Eterm arg2);
1608 Eterm erts_int_rem(Process* p, Eterm arg1, Eterm arg2);
1609 Eterm erts_bxor(Process* p, Eterm arg1, Eterm arg2);
1610 Eterm erts_bsr(Process* p, Eterm arg1, Eterm arg2);
1611 Eterm erts_bsl(Process* p, Eterm arg1, Eterm arg2);
1612 Eterm erts_bnot(Process* p, Eterm arg);
1613 Eterm erts_bor(Process* p, Eterm arg1, Eterm arg2);
1614 Eterm erts_band(Process* p, Eterm arg1, Eterm arg2);
1615
1616 Eterm erts_gc_mixed_plus(Process* p, Eterm* reg, Uint live);
1617 Eterm erts_gc_mixed_minus(Process* p, Eterm* reg, Uint live);
1618 Eterm erts_gc_mixed_times(Process* p, Eterm* reg, Uint live);
1619 Eterm erts_gc_mixed_div(Process* p, Eterm* reg, Uint live);
1620 Eterm erts_gc_int_div(Process* p, Eterm* reg, Uint live);
1621 Eterm erts_gc_int_rem(Process* p, Eterm* reg, Uint live);
1622 Eterm erts_gc_band(Process* p, Eterm* reg, Uint live);
1623 Eterm erts_gc_bor(Process* p, Eterm* reg, Uint live);
1624 Eterm erts_gc_bxor(Process* p, Eterm* reg, Uint live);
1625 Eterm erts_gc_bnot(Process* p, Eterm* reg, Uint live);
1626
1627 Uint erts_current_reductions(Process* current, Process *p);
1628
1629 int erts_print_system_version(fmtfn_t to, void *arg, Process *c_p);
1630
1631 int erts_hibernate(Process* c_p, Eterm* reg);
1632
1633 ERTS_GLB_FORCE_INLINE int erts_is_literal(Eterm tptr, Eterm *ptr);
1634
1635 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
1636
erts_is_literal(Eterm tptr,Eterm * ptr)1637 ERTS_GLB_FORCE_INLINE int erts_is_literal(Eterm tptr, Eterm *ptr)
1638 {
1639 ASSERT(is_boxed(tptr) || is_list(tptr));
1640 ASSERT(ptr == ptr_val(tptr));
1641
1642 #if defined(ERTS_HAVE_IS_IN_LITERAL_RANGE)
1643 return erts_is_in_literal_range(ptr);
1644 #elif defined(TAG_LITERAL_PTR)
1645 return is_literal_ptr(tptr);
1646 #else
1647 # error Not able to detect literals...
1648 #endif
1649
1650 }
1651
1652 #endif
1653
1654 Eterm erts_msacc_request(Process *c_p, int action, Eterm *threads);
1655
1656 /*
1657 ** Call_trace uses this API for the parameter matching functions
1658 */
1659
1660 #define MatchSetRef(MPSP) \
1661 do { \
1662 if ((MPSP) != NULL) { \
1663 erts_refc_inc(&(MPSP)->intern.refc, 1); \
1664 } \
1665 } while (0)
1666
1667 #define MatchSetUnref(MPSP) \
1668 do { \
1669 if (((MPSP) != NULL)) { \
1670 erts_bin_release(MPSP); \
1671 } \
1672 } while(0)
1673
1674 #define MatchSetGetSource(MPSP) erts_match_set_get_source(MPSP)
1675
1676 extern Binary *erts_match_set_compile(Process *p, Eterm matchexpr, Eterm MFA,
1677 Uint *freasonp);
1678 extern void erts_match_set_release_result(Process* p);
1679 ERTS_GLB_INLINE void erts_match_set_release_result_trace(Process* p, Eterm);
1680
1681 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
1682 ERTS_GLB_INLINE
erts_match_set_release_result_trace(Process * p,Eterm pam_result)1683 void erts_match_set_release_result_trace(Process* p, Eterm pam_result)
1684 {
1685 if (is_not_immed(pam_result))
1686 erts_match_set_release_result(p);
1687 }
1688 #endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
1689
1690 enum erts_pam_run_flags {
1691 ERTS_PAM_TMP_RESULT=1,
1692 ERTS_PAM_COPY_RESULT=2,
1693 ERTS_PAM_CONTIGUOUS_TUPLE=4,
1694 ERTS_PAM_IGNORE_TRACE_SILENT=8
1695 };
1696 extern Eterm erts_match_set_run_trace(Process *p,
1697 Process *self,
1698 Binary *mpsp,
1699 Eterm *args, int num_args,
1700 enum erts_pam_run_flags in_flags,
1701 Uint32 *return_flags);
1702 extern Eterm erts_match_set_get_source(Binary *mpsp);
1703 extern void erts_match_prog_foreach_offheap(Binary *b,
1704 void (*)(ErlOffHeap *, void *),
1705 void *);
1706
1707 #define MATCH_SET_RETURN_TRACE (0x1) /* return trace requested */
1708 #define MATCH_SET_RETURN_TO_TRACE (0x2) /* Misleading name, it is not actually
1709 set by the match program, but by the
1710 breakpoint functions */
1711 #define MATCH_SET_EXCEPTION_TRACE (0x4) /* exception trace requested */
1712 #define MATCH_SET_RX_TRACE (MATCH_SET_RETURN_TRACE|MATCH_SET_EXCEPTION_TRACE)
1713
1714 extern erts_driver_t vanilla_driver;
1715 extern erts_driver_t spawn_driver;
1716 extern erts_driver_t forker_driver;
1717 extern erts_driver_t fd_driver;
1718
1719 int erts_beam_jump_table(void);
1720
1721 #define DeclareTmpHeap(VariableName,Size,Process) \
1722 Eterm VariableName[Size]
1723 #define DeclareTypedTmpHeap(Type,VariableName,Process) \
1724 Type VariableName[1]
1725 #define DeclareTmpHeapNoproc(VariableName,Size) \
1726 Eterm VariableName[Size]
1727 #define UseTmpHeap(Size,Proc) /* Nothing */
1728 #define UnUseTmpHeap(Size,Proc) /* Nothing */
1729 #define UseTmpHeapNoproc(Size) /* Nothing */
1730 #define UnUseTmpHeapNoproc(Size) /* Nothing */
1731
1732 ERTS_GLB_INLINE void dtrace_pid_str(Eterm pid, char *process_buf);
1733 ERTS_GLB_INLINE void dtrace_proc_str(Process *process, char *process_buf);
1734 ERTS_GLB_INLINE void dtrace_port_str(Port *port, char *port_buf);
1735 ERTS_GLB_INLINE void dtrace_fun_decode(Process *process, ErtsCodeMFA *mfa,
1736 char *process_buf, char *mfa_buf);
1737
1738 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
1739
1740 #include "dtrace-wrapper.h"
1741
1742 ERTS_GLB_INLINE void
dtrace_pid_str(Eterm pid,char * process_buf)1743 dtrace_pid_str(Eterm pid, char *process_buf)
1744 {
1745 if (is_pid(pid))
1746 erts_snprintf(process_buf, DTRACE_TERM_BUF_SIZE, "<%lu.%lu.%lu>",
1747 pid_channel_no(pid),
1748 pid_number(pid),
1749 pid_serial(pid));
1750 else if (is_port(pid))
1751 erts_snprintf(process_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%b64u>",
1752 port_channel_no(pid),
1753 port_number(pid));
1754 }
1755
1756 ERTS_GLB_INLINE void
dtrace_proc_str(Process * process,char * process_buf)1757 dtrace_proc_str(Process *process, char *process_buf)
1758 {
1759 dtrace_pid_str(process->common.id, process_buf);
1760 }
1761
1762 ERTS_GLB_INLINE void
dtrace_port_str(Port * port,char * port_buf)1763 dtrace_port_str(Port *port, char *port_buf)
1764 {
1765 dtrace_pid_str(port->common.id, port_buf);
1766 }
1767
1768 ERTS_GLB_INLINE void
dtrace_fun_decode(Process * process,ErtsCodeMFA * mfa,char * process_buf,char * mfa_buf)1769 dtrace_fun_decode(Process *process, ErtsCodeMFA *mfa,
1770 char *process_buf, char *mfa_buf)
1771 {
1772 if (process_buf) {
1773 dtrace_proc_str(process, process_buf);
1774 }
1775
1776 erts_snprintf(mfa_buf, DTRACE_TERM_BUF_SIZE, "%T:%T/%d",
1777 mfa->module, mfa->function, mfa->arity);
1778 }
1779
1780 #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */
1781
1782 #endif /* !__GLOBAL_H__ */
1783