📄 erl_fun.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$ */#ifdef HAVE_CONFIG_H# include "config.h"#endif#include "sys.h"#include "erl_vm.h"#include "global.h"#include "erl_fun.h"#include "hash.h"static Hash erts_fun_table;#include "erl_smp.h"static erts_smp_rwmtx_t erts_fun_table_lock;#define erts_fun_read_lock() erts_smp_rwmtx_rlock(&erts_fun_table_lock)#define erts_fun_read_unlock() erts_smp_rwmtx_runlock(&erts_fun_table_lock)#define erts_fun_write_lock() erts_smp_rwmtx_rwlock(&erts_fun_table_lock)#define erts_fun_write_unlock() erts_smp_rwmtx_rwunlock(&erts_fun_table_lock)#define erts_fun_init_lock() erts_smp_rwmtx_init(&erts_fun_table_lock, \ "fun_tab")static HashValue fun_hash(ErlFunEntry* obj);static int fun_cmp(ErlFunEntry* obj1, ErlFunEntry* obj2);static ErlFunEntry* fun_alloc(ErlFunEntry* template);static void fun_free(ErlFunEntry* obj);/* * The address field of every fun that has no loaded code will point * to unloaded_fun[]. The -1 in unloaded_fun[0] will be interpreted * as an illegal arity when attempting to call a fun. */static Eterm unloaded_fun_code[3] = {NIL, -1, 0};static Eterm* unloaded_fun = unloaded_fun_code + 2;voiderts_init_fun_table(void){ HashFunctions f; erts_fun_init_lock(); f.hash = (H_FUN) fun_hash; f.cmp = (HCMP_FUN) fun_cmp; f.alloc = (HALLOC_FUN) fun_alloc; f.free = (HFREE_FUN) fun_free; hash_init(ERTS_ALC_T_FUN_TABLE, &erts_fun_table, "fun_table", 16, f);}voiderts_fun_info(int to, void *to_arg){ int lock = !ERTS_IS_CRASH_DUMPING; if (lock) erts_fun_read_lock(); hash_info(to, to_arg, &erts_fun_table); if (lock) erts_fun_read_unlock();}int erts_fun_table_sz(void){ int sz; int lock = !ERTS_IS_CRASH_DUMPING; if (lock) erts_fun_read_lock(); sz = hash_table_sz(&erts_fun_table); if (lock) erts_fun_read_unlock(); return sz;}ErlFunEntry*erts_put_fun_entry(Eterm mod, int uniq, int index){ ErlFunEntry template; ErlFunEntry* fe; long refc; ASSERT(is_atom(mod)); template.old_uniq = uniq; template.old_index = index; template.module = mod; erts_fun_write_lock(); fe = (ErlFunEntry *) hash_put(&erts_fun_table, (void*) &template); sys_memset(fe->uniq, 0, sizeof(fe->uniq)); fe->index = 0; refc = erts_refc_inctest(&fe->refc, 0); if (refc < 2) /* New or pending delete */ erts_refc_inc(&fe->refc, 1); erts_fun_write_unlock(); return fe;}ErlFunEntry*erts_put_fun_entry2(Eterm mod, int old_uniq, int old_index, byte* uniq, int index, int arity){ ErlFunEntry template; ErlFunEntry* fe; long refc; ASSERT(is_atom(mod)); template.old_uniq = old_uniq; template.old_index = old_index; template.module = mod; erts_fun_write_lock(); fe = (ErlFunEntry *) hash_put(&erts_fun_table, (void*) &template); sys_memcpy(fe->uniq, uniq, sizeof(fe->uniq)); fe->index = index; fe->arity = arity; refc = erts_refc_inctest(&fe->refc, 0); if (refc < 2) /* New or pending delete */ erts_refc_inc(&fe->refc, 1); erts_fun_write_unlock(); return fe;}struct my_key { Eterm mod; byte* uniq; int index; ErlFunEntry* fe;};ErlFunEntry*erts_get_fun_entry(Eterm mod, int uniq, int index){ ErlFunEntry template; ErlFunEntry *ret; ASSERT(is_atom(mod)); template.old_uniq = uniq; template.old_index = index; template.module = mod; erts_fun_read_lock(); ret = (ErlFunEntry *) hash_get(&erts_fun_table, (void*) &template); if (ret) { long refc = erts_refc_inctest(&ret->refc, 1); if (refc < 2) /* Pending delete */ erts_refc_inc(&ret->refc, 1); } erts_fun_read_unlock(); return ret;}static voiderts_erase_fun_entry_unlocked(ErlFunEntry* fe){ hash_erase(&erts_fun_table, (void *) fe);}voiderts_erase_fun_entry(ErlFunEntry* fe){ erts_fun_write_lock();#ifdef ERTS_SMP /* * We have to check refc again since someone might have looked up * the fun entry and incremented refc after last check. */ if (erts_refc_dectest(&fe->refc, -1) <= 0)#endif { if (fe->address != unloaded_fun) erl_exit(1, "Internal error: " "Invalid reference count found on #Fun<%T.%d.%d>: " " About to erase fun still referred by code.\n", fe->module, fe->old_index, fe->old_uniq); erts_erase_fun_entry_unlocked(fe); } erts_fun_write_unlock();}#ifndef HYBRID /* FIND ME! */voiderts_cleanup_funs(ErlFunThing* funp){ while (funp) { ErlFunEntry* fe = funp->fe; if (erts_refc_dectest(&fe->refc, 0) == 0) { erts_erase_fun_entry(fe); } funp = funp->next; }}#endifvoiderts_cleanup_funs_on_purge(Eterm* start, Eterm* end){ int limit; HashBucket** bucket; ErlFunEntry* to_delete = NULL; int i; erts_fun_write_lock(); limit = erts_fun_table.size; bucket = erts_fun_table.bucket; for (i = 0; i < limit; i++) { HashBucket* b = bucket[i]; while (b) { ErlFunEntry* fe = (ErlFunEntry *) b; Eterm* addr = fe->address; if (start <= addr && addr < end) { fe->address = unloaded_fun; if (erts_refc_dectest(&fe->refc, 0) == 0) { fe->address = (void *) to_delete; to_delete = fe; } } b = b->next; } } while (to_delete != NULL) { ErlFunEntry* next = (ErlFunEntry *) to_delete->address; erts_erase_fun_entry_unlocked(to_delete); to_delete = next; } erts_fun_write_unlock();}voiderts_dump_fun_entries(int to, void *to_arg){ int limit; HashBucket** bucket; int i; int lock = !ERTS_IS_CRASH_DUMPING; if (lock) erts_fun_read_lock(); limit = erts_fun_table.size; bucket = erts_fun_table.bucket; for (i = 0; i < limit; i++) { HashBucket* b = bucket[i]; while (b) { ErlFunEntry* fe = (ErlFunEntry *) b; erts_print(to, to_arg, "=fun\n"); erts_print(to, to_arg, "Module: %T\n", fe->module); erts_print(to, to_arg, "Uniq: %d\n", fe->old_uniq); erts_print(to, to_arg, "Index: %d\n",fe->old_index); erts_print(to, to_arg, "Address: %p\n", fe->address);#ifdef HIPE erts_print(to, to_arg, "Native_address: %p\n", fe->native_address);#endif erts_print(to, to_arg, "Refc: %d\n", erts_refc_read(&fe->refc, 1)); b = b->next; } } if (lock) erts_fun_read_unlock();}static HashValuefun_hash(ErlFunEntry* obj){ return (HashValue) (obj->old_uniq ^ obj->old_index ^ atom_val(obj->module));}static intfun_cmp(ErlFunEntry* obj1, ErlFunEntry* obj2){ return !(obj1->module == obj2->module && obj1->old_uniq == obj2->old_uniq && obj1->old_index == obj2->old_index);}static ErlFunEntry*fun_alloc(ErlFunEntry* template){ ErlFunEntry* obj = (ErlFunEntry *) erts_alloc(ERTS_ALC_T_FUN_ENTRY, sizeof(ErlFunEntry)); obj->old_uniq = template->old_uniq; obj->old_index = template->old_index; obj->module = template->module; erts_refc_init(&obj->refc, -1); obj->address = unloaded_fun;#ifdef HIPE obj->native_address = NULL;#endif return obj;}static voidfun_free(ErlFunEntry* obj){ erts_free(ERTS_ALC_T_FUN_ENTRY, (void *) obj);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -