📄 erl_db_util.c
字号:
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' * * $Id$ *//* * Common utilities for the different types of db tables. * Mostly matching etc. */#ifdef HAVE_CONFIG_H# include "config.h"#endif#include "sys.h"#include "erl_vm.h"#include "global.h"#include "erl_process.h"#include "error.h"#define ERTS_WANT_DB_INTERNAL__#include "erl_db.h"#include "bif.h"#include "big.h"#include "erl_binary.h"#include "erl_db_util.h"/*** Flags for the guard bif's*//* These are offsets from the DCOMP_* value */#define DBIF_GUARD 1#define DBIF_BODY 0/* These are the DBIF flag bits corresponding to the DCOMP_* value. * If a bit is set, the BIF is allowed in that context. */#define DBIF_TABLE_GUARD (1 << (DCOMP_TABLE + DBIF_GUARD))#define DBIF_TABLE_BODY (1 << (DCOMP_TABLE + DBIF_BODY))#define DBIF_TRACE_GUARD (1 << (DCOMP_TRACE + DBIF_GUARD))#define DBIF_TRACE_BODY (1 << (DCOMP_TRACE + DBIF_BODY))#define DBIF_ALL \DBIF_TABLE_GUARD | DBIF_TABLE_BODY | DBIF_TRACE_GUARD | DBIF_TRACE_BODY/*** Some convenience macros for stacks (DMC == db_match_compile)*/#define DMC_DEFAULT_SIZE 25#define DMC_STACK_TYPE(Type) DMC_##Type##_stack#define DMC_DECLARE_STACK_TYPE(Type) \typedef struct DMC_STACK_TYPE(Type) { \ int pos; \ int siz; \ Type def[DMC_DEFAULT_SIZE]; \ Type *data; \} DMC_STACK_TYPE(Type) #define DMC_INIT_STACK(Name) \ (Name).pos = 0; (Name).siz = DMC_DEFAULT_SIZE; (Name).data = (Name).def#define DMC_STACK_DATA(Name) (Name).data#define DMC_STACK_NUM(Name) (Name).pos#define DMC_PUSH(On, What) \do { \ if ((On).pos >= (On).siz) { \ (On).siz *= 2; \ (On).data \ = (((On).def == (On).data) \ ? memcpy(erts_alloc(ERTS_ALC_T_DB_MC_STK, \ (On).siz*sizeof(*((On).data))), \ (On).def, \ DMC_DEFAULT_SIZE*sizeof(*((On).data))) \ : erts_realloc(ERTS_ALC_T_DB_MC_STK, \ (void *) (On).data, \ (On).siz*sizeof(*((On).data)))); \ } \ (On).data[(On).pos++] = What; \} while (0)#define DMC_POP(From) (From).data[--(From).pos]#define DMC_TOP(From) (From).data[(From).pos - 1]#define DMC_EMPTY(Name) ((Name).pos == 0)#define DMC_PEEK(On, At) (On).data[At] #define DMC_POKE(On, At, Value) ((On).data[At] = (Value))#define DMC_CLEAR(Name) (Name).pos = 0#define DMC_FREE(Name) \do { \ if ((Name).def != (Name).data) \ erts_free(ERTS_ALC_T_DB_MC_STK, (Name).data); \} while (0)static ERTS_INLINE Process *get_proc(Process *cp, Uint32 cp_locks, Eterm id, Uint32 id_locks){ Process *proc = erts_pid2proc(cp, cp_locks, id, id_locks); if (!proc && is_atom(id)) proc = erts_whereis_process(cp, cp_locks, id, id_locks, 0); return proc;}static Etermset_tracee_flags(Process *tracee_p, Eterm tracer, Uint d_flags, Uint e_flags) { Eterm ret; Uint flags; if (tracer == NIL) { flags = tracee_p->trace_flags & ~TRACEE_FLAGS; } else { flags = ((tracee_p->trace_flags & ~d_flags) | e_flags); if (! flags) tracer = NIL; } ret = tracee_p->tracer_proc != tracer || tracee_p->trace_flags != flags ? am_true : am_false; tracee_p->tracer_proc = tracer; tracee_p->trace_flags = flags; return ret;}/*** Assuming all locks on tracee_p on entry**** Changes tracee_p->trace_flags and tracee_p->tracer_proc** according to input disable/enable flags and tracer.**** Returns am_true|am_false on success, am_true if value changed,** returns fail_term on failure. Fails if tracer pid or port is invalid.*/static Eterm set_match_trace(Process *tracee_p, Eterm fail_term, Eterm tracer, Uint d_flags, Uint e_flags) { Eterm ret = fail_term; Process *tracer_p; ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCKS_ALL == erts_proc_lc_my_proc_locks(tracee_p)); if (is_internal_pid(tracer) && (tracer_p = erts_pid2proc(tracee_p, ERTS_PROC_LOCKS_ALL, tracer, ERTS_PROC_LOCKS_ALL))) { if (tracee_p != tracer_p) { ret = set_tracee_flags(tracee_p, tracer, d_flags, e_flags); tracer_p->trace_flags |= tracee_p->trace_flags ? F_TRACER : 0; erts_smp_proc_unlock(tracer_p, ERTS_PROC_LOCKS_ALL); } } else if (is_internal_port(tracer)) { Port *tracer_port = erts_id2port(tracer, tracee_p, ERTS_PROC_LOCKS_ALL); if (tracer_port) { if (! INVALID_TRACER_PORT(tracer_port, tracer)) { ret = set_tracee_flags(tracee_p, tracer, d_flags, e_flags); } erts_smp_port_unlock(tracer_port); } } else { ASSERT(is_nil(tracer)); ret = set_tracee_flags(tracee_p, tracer, d_flags, e_flags); } return ret;}/* Type checking... */#define BOXED_IS_TUPLE(Boxed) is_arity_value(*boxed_val((Boxed)))/***** Types and enum's (compiled matches)***//*** match VM instructions*/typedef enum { matchArray, /* Only when parameter is an array (DCOMP_TRACE) */ matchArrayBind, /* ------------- " ------------ */ matchTuple, matchPushT, matchPushL, matchPop, matchBind, matchCmp, matchEqBin, matchEqFloat, matchEqBig, matchEqRef, matchEq, matchList, matchSkip, matchPushC, matchConsA, /* Car is below Cdr */ matchConsB, /* Cdr is below Car (unusual) */ matchMkTuple, matchCall0, matchCall1, matchCall2, matchCall3, matchPushV, matchPushExpr, /* Push the whole expression we're matching ('$_') */ matchPushArrayAsList, /* Only when parameter is an Array and not an erlang term (DCOMP_TRACE) */ matchPushArrayAsListU, /* As above but unknown size */ matchTrue, matchOr, matchAnd, matchOrElse, matchAndThen, matchSelf, matchWaste, matchReturn, matchProcessDump, matchDisplay, matchIsSeqTrace, matchSetSeqToken, matchGetSeqToken, matchSetReturnTrace, matchSetExceptionTrace, matchCatch, matchEnableTrace, matchDisableTrace, matchEnableTrace2, matchDisableTrace2, matchTryMeElse, matchCaller, matchHalt, matchSilent, matchSetSeqTokenFake, matchTrace2, matchTrace3} MatchOps;/*** Guard bif's*/typedef struct dmc_guard_bif { Eterm name; /* atom */ void *biff; /* BIF_RETTYPE (*biff)(); */ int arity; Uint32 flags;} DMCGuardBif; /*** Error information (for lint)*//*** Type declarations for stacks*/DMC_DECLARE_STACK_TYPE(Eterm);DMC_DECLARE_STACK_TYPE(Uint);DMC_DECLARE_STACK_TYPE(unsigned);/*** Data about the heap during compilation*/typedef struct DMCHeap { int size; unsigned def[DMC_DEFAULT_SIZE]; unsigned *data; int used;} DMCHeap;/*** Return values from sub compilation steps (guard compilation)*/typedef enum dmc_ret { retOk, retFail, retRestart } DMCRet; /*** Diverse context information*/typedef struct dmc_context { int stack_need; int stack_used; ErlHeapFragment *save; ErlHeapFragment *copy; Eterm *matchexpr; Eterm *guardexpr; Eterm *bodyexpr; int num_match; int current_match; int eheap_need; Uint cflags; DMC_STACK_TYPE(Uint) *labels; int is_guard; /* 1 if in guard, 0 if in body */ int special; /* 1 if the head in the match was a single expression */ DMCErrInfo *err_info;} DMCContext;/***** Global variables ***//*** Internal*//* ** The pseudo process used by the VM (pam).*/#define ERTS_DEFAULT_MS_HEAP_SIZE 128typedef struct { Process process; Eterm *heap; Eterm default_heap[ERTS_DEFAULT_MS_HEAP_SIZE];} ErtsMatchPseudoProcess;#ifdef ERTS_SMPstatic erts_smp_tsd_key_t match_pseudo_process_key;#elsestatic ErtsMatchPseudoProcess *match_pseudo_process;#endifstatic ERTS_INLINE voidcleanup_match_pseudo_process(ErtsMatchPseudoProcess *mpsp, int keep_heap){ if (mpsp->process.mbuf || mpsp->process.off_heap.mso#ifndef HYBRID /* FIND ME! */ || mpsp->process.off_heap.funs#endif || mpsp->process.off_heap.externals) { erts_cleanup_empty_process(&mpsp->process); }#ifdef DEBUG else { erts_debug_verify_clean_empty_process(&mpsp->process); }#endif if (!keep_heap) { if (mpsp->heap != &mpsp->default_heap[0]) { /* Have to be done *after* call to erts_cleanup_empty_process() */ erts_free(ERTS_ALC_T_DB_MS_RUN_HEAP, (void *) mpsp->heap); mpsp->heap = &mpsp->default_heap[0]; }#ifdef DEBUG else { int i; for (i = 0; i < ERTS_DEFAULT_MS_HEAP_SIZE; i++) {#ifdef ARCH_64 mpsp->default_heap[i] = (Eterm) 0xdeadbeefdeadbeef;#else mpsp->default_heap[i] = (Eterm) 0xdeadbeef;#endif } }#endif }}static ErtsMatchPseudoProcess *create_match_pseudo_process(void){ ErtsMatchPseudoProcess *mpsp; mpsp = (ErtsMatchPseudoProcess *)erts_alloc(ERTS_ALC_T_DB_MS_PSDO_PROC, sizeof(ErtsMatchPseudoProcess)); erts_init_empty_process(&mpsp->process); mpsp->heap = &mpsp->default_heap[0]; return mpsp;}static ERTS_INLINE ErtsMatchPseudoProcess *get_match_pseudo_process(Process *c_p, Uint heap_size){ ErtsMatchPseudoProcess *mpsp;#ifdef ERTS_SMP mpsp = (ErtsMatchPseudoProcess *) c_p->scheduler_data->match_pseudo_process; if (mpsp) cleanup_match_pseudo_process(mpsp, 0); else { ASSERT(erts_smp_tsd_get(match_pseudo_process_key) == NULL); mpsp = create_match_pseudo_process(); c_p->scheduler_data->match_pseudo_process = (void *) mpsp; erts_smp_tsd_set(match_pseudo_process_key, (void *) mpsp); } ASSERT(mpsp == erts_smp_tsd_get(match_pseudo_process_key)); mpsp->process.scheduler_data = c_p->scheduler_data;#else mpsp = match_pseudo_process; cleanup_match_pseudo_process(mpsp, 0);#endif if (heap_size > ERTS_DEFAULT_MS_HEAP_SIZE) mpsp->heap = (Eterm *) erts_alloc(ERTS_ALC_T_DB_MS_RUN_HEAP, heap_size*sizeof(Uint)); else { ASSERT(mpsp->heap == &mpsp->default_heap[0]); } return mpsp;}#ifdef ERTS_SMPstatic voiddestroy_match_pseudo_process(void){ ErtsMatchPseudoProcess *mpsp; mpsp = (ErtsMatchPseudoProcess *)erts_smp_tsd_get(match_pseudo_process_key); if (mpsp) { cleanup_match_pseudo_process(mpsp, 0); erts_free(ERTS_ALC_T_DB_MS_PSDO_PROC, (void *) mpsp); erts_smp_tsd_set(match_pseudo_process_key, (void *) NULL); }}#endifstaticvoidmatch_pseudo_process_init(void){#ifdef ERTS_SMP erts_smp_tsd_key_create(&match_pseudo_process_key); erts_smp_install_exit_handler(destroy_match_pseudo_process);#else match_pseudo_process = create_match_pseudo_process();#endif}voiderts_match_set_release_result(Process* c_p){ (void) get_match_pseudo_process(c_p, 0); /* Clean it up */}/* The trace control word. */static erts_smp_atomic_t trace_control_word;Etermerts_ets_copy_object(Eterm obj, Process* to){ Uint size = size_object(obj); Eterm* hp = HAlloc(to, size); Eterm res; res = copy_struct(obj, size, &hp, &MSO(to));#ifdef DEBUG if (eq(obj, res) == 0) { erl_exit(1, "copy not equal to source\n"); }#endif return res;}/* This needs to be here, before the bif table... */static Eterm db_set_trace_control_word_fake_1(Process *p, Eterm val);/*** The table of callable bif's, i e guard bif's and ** some special animals that can provide us with trace** information. This array is sorted on init.*/static DMCGuardBif guard_tab[] ={ { am_is_atom, &is_atom_1, 1, DBIF_ALL }, { am_is_constant, &is_constant_1, 1, DBIF_ALL }, { am_is_float, &is_float_1, 1, DBIF_ALL }, { am_is_integer, &is_integer_1, 1, DBIF_ALL }, { am_is_list, &is_list_1, 1, DBIF_ALL }, { am_is_number, &is_number_1, 1, DBIF_ALL }, { am_is_pid, &is_pid_1, 1, DBIF_ALL }, { am_is_port, &is_port_1, 1, DBIF_ALL }, { am_is_reference, &is_reference_1, 1, DBIF_ALL }, { am_is_tuple, &is_tuple_1, 1, DBIF_ALL }, { am_is_binary, &is_binary_1, 1, DBIF_ALL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -