⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 erl_bif_timer.c

📁 OTP是开放电信平台的简称
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ``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 "erl_bif_timer.h"#include "global.h"#include "bif.h"#include "error.h"#include "big.h"/****************************************************************************** BIF Timer support****************************************************************************/#define BTM_FLG_SL_TIMER	(((Uint32) 1) << 0)#define BTM_FLG_CANCELED	(((Uint32) 1) << 1)#define BTM_FLG_HEAD		(((Uint32) 1) << 2)#define BTM_FLG_BYNAME		(((Uint32) 1) << 3)#define BTM_FLG_WRAP		(((Uint32) 1) << 4)struct ErtsBifTimer_ {    struct {	union {	    ErtsBifTimer **head;	    ErtsBifTimer *prev;	} u;	ErtsBifTimer *next;    } tab;    union {	Eterm name;	struct {	    ErtsBifTimer *prev;	    ErtsBifTimer *next;	    Process *ess;	} proc;    } receiver;    ErlTimer tm;    ErlHeapFragment* bp;    Uint32 flags;    Eterm message;    Uint32 ref_numbers[ERTS_REF_NUMBERS];};#ifdef SMALL_MEMORY#define TIMER_HASH_VEC_SZ	3331#define BTM_PREALC_SZ		10#else#define TIMER_HASH_VEC_SZ	10007#define BTM_PREALC_SZ		100#endifstatic ErtsBifTimer **bif_timer_tab;  static Uint no_bif_timers;static erts_smp_rwmtx_t bif_timer_lock;#define erts_smp_safe_btm_rwlock(P, L) \	safe_btm_lock((P), (L), 1)#define erts_smp_safe_btm_rlock(P, L) \	safe_btm_lock((P), (L), 0)#define erts_smp_btm_rwlock() \	erts_smp_rwmtx_rwlock(&bif_timer_lock)#define erts_smp_btm_tryrwlock() \	erts_smp_rwmtx_tryrwlock(&bif_timer_lock)#define erts_smp_btm_rwunlock() \	erts_smp_rwmtx_rwunlock(&bif_timer_lock)#define erts_smp_btm_rlock() \	erts_smp_rwmtx_rlock(&bif_timer_lock)#define erts_smp_btm_tryrlock() \	erts_smp_rwmtx_tryrlock(&bif_timer_lock)#define erts_smp_btm_runlock() \	erts_smp_rwmtx_runlock(&bif_timer_lock)#define erts_smp_btm_lock_init() \	erts_smp_rwmtx_init(&bif_timer_lock, "bif_timers")static ERTS_INLINE intsafe_btm_lock(Process *c_p, Uint32 c_p_locks, int rw_lock){    ASSERT(c_p && c_p_locks);#ifdef ERTS_SMP    if ((rw_lock ? erts_smp_btm_tryrwlock() : erts_smp_btm_tryrlock()) != EBUSY)	return 0;    erts_smp_proc_unlock(c_p, c_p_locks);    if (rw_lock)	erts_smp_btm_rwlock();    else	erts_smp_btm_rlock();    erts_smp_proc_lock(c_p, c_p_locks);    if (ERTS_PROC_IS_EXITING(c_p)) {	if (rw_lock)	    erts_smp_btm_rwunlock();	else	    erts_smp_btm_runlock();	return 1;    }#endif    return 0;}ERTS_SMP_PALLOC_IMPL(btm_pre, ErtsBifTimer, BTM_PREALC_SZ)static ERTS_INLINE intget_index(Uint32 *ref_numbers, Uint32 len){    Uint32 hash;    /* len can potentially be larger than ERTS_REF_NUMBERS       if it has visited another node... */    if (len > ERTS_REF_NUMBERS)	len = ERTS_REF_NUMBERS;#if ERTS_REF_NUMBERS != 3#error "ERTS_REF_NUMBERS changed. Update me..."#endif    switch (len) {    case 3: if (!ref_numbers[2]) len = 2;    case 2: if (!ref_numbers[1]) len = 1;    default:  break;    }    ASSERT(1 <= len && len <= ERTS_REF_NUMBERS);    hash = block_hash((byte *) ref_numbers, len * sizeof(Uint32), 0x08d12e65);    return (int) (hash % ((Uint32) TIMER_HASH_VEC_SZ));}static Etermcreate_ref(Uint *hp, Uint32 *ref_numbers, Uint32 len){    Uint32 *datap;    int i;    if (len > ERTS_MAX_REF_NUMBERS) {	/* Such large refs should no be able to appear in the emulator */	erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__);    }#ifdef ARCH_64    hp[0] = make_ref_thing_header(len/2 + 1);    datap = (Uint32 *) &hp[1];    *(datap++) = len;#else    hp[0] = make_ref_thing_header(len);    datap = (Uint32 *) &hp[1];#endif    for (i = 0; i < len; i++)	datap[i] = ref_numbers[i];    return make_internal_ref(hp);}static inteq_non_standard_ref_numbers(Uint32 *rn1, Uint32 len1, Uint32 *rn2, Uint32 len2){#ifdef ARCH_64#define MAX_REF_HEAP_SZ (1+(ERTS_MAX_REF_NUMBERS/2+1))#else#define MAX_REF_HEAP_SZ (1+ERTS_MAX_REF_NUMBERS)#endif    Uint r1_hp[MAX_REF_HEAP_SZ];    Uint r2_hp[MAX_REF_HEAP_SZ];    return eq(create_ref(r1_hp, rn1, len1), create_ref(r2_hp, rn2, len2));#undef MAX_REF_HEAP_SZ}static ERTS_INLINE inteq_ref_numbers(Uint32 *rn1, Uint32 len1, Uint32 *rn2, Uint32 len2){    int res;    if (len1 != ERTS_REF_NUMBERS || len2 != ERTS_REF_NUMBERS) {	/* Can potentially happen, but will never... */	return eq_non_standard_ref_numbers(rn1, len1, rn2, len2);    }#if ERTS_REF_NUMBERS != 3#error "ERTS_REF_NUMBERS changed. Update me..."#endif    res = rn1[0] == rn2[0] && rn1[1] == rn2[1] && rn1[2] == rn2[2];    ASSERT(res	   ? eq_non_standard_ref_numbers(rn1, len1, rn2, len2)	   : !eq_non_standard_ref_numbers(rn1, len1, rn2, len2));    return res;}static ERTS_INLINE ErtsBifTimer *tab_find(Eterm ref){    Uint32 *ref_numbers = internal_ref_numbers(ref);    Uint32 ref_numbers_len = internal_ref_no_of_numbers(ref);    int ix = get_index(ref_numbers, ref_numbers_len);    ErtsBifTimer* btm;    for (btm = bif_timer_tab[ix]; btm; btm = btm->tab.next)	if (eq_ref_numbers(ref_numbers, ref_numbers_len,			   btm->ref_numbers, ERTS_REF_NUMBERS))	    return btm;    return NULL;}static ERTS_INLINE voidtab_remove(ErtsBifTimer* btm){    if (btm->flags & BTM_FLG_HEAD) {	*btm->tab.u.head = btm->tab.next;	if (btm->tab.next) {	    btm->tab.next->flags |= BTM_FLG_HEAD;	    btm->tab.next->tab.u.head = btm->tab.u.head;	}    }    else {	btm->tab.u.prev->tab.next = btm->tab.next;	if (btm->tab.next)	    btm->tab.next->tab.u.prev = btm->tab.u.prev;    }    btm->flags |= BTM_FLG_CANCELED;    ASSERT(no_bif_timers > 0);    no_bif_timers--;}static ERTS_INLINE voidtab_insert(ErtsBifTimer* btm){    int ix = get_index(btm->ref_numbers, ERTS_REF_NUMBERS);    ErtsBifTimer* btm_list = bif_timer_tab[ix];    if (btm_list) {	btm_list->flags &= ~BTM_FLG_HEAD;	btm_list->tab.u.prev = btm;    }    btm->flags |= BTM_FLG_HEAD;    btm->tab.u.head = &bif_timer_tab[ix];    btm->tab.next = btm_list;    bif_timer_tab[ix] = btm;    no_bif_timers++;}static ERTS_INLINE voidlink_proc(Process *p, ErtsBifTimer* btm){    btm->receiver.proc.ess = p;    btm->receiver.proc.prev = NULL;    btm->receiver.proc.next = p->bif_timers;    if (p->bif_timers)		p->bif_timers->receiver.proc.prev = btm;    p->bif_timers = btm;}static ERTS_INLINE voidunlink_proc(ErtsBifTimer* btm){    if (btm->receiver.proc.prev)	btm->receiver.proc.prev->receiver.proc.next = btm->receiver.proc.next;    else	btm->receiver.proc.ess->bif_timers = btm->receiver.proc.next;    if (btm->receiver.proc.next)	btm->receiver.proc.next->receiver.proc.prev = btm->receiver.proc.prev;}static voidbif_timer_cleanup(ErtsBifTimer* btm){    ASSERT(btm);    if (btm->bp)	free_message_buffer(btm->bp);    ERTS_PROC_LESS_MEM(sizeof(ErtsBifTimer));    if (!btm_pre_free(btm)) {	if (btm->flags & BTM_FLG_SL_TIMER)	    erts_free(ERTS_ALC_T_SL_BIF_TIMER, (void *) btm);	else	    erts_free(ERTS_ALC_T_LL_BIF_TIMER, (void *) btm);    }}static voidbif_timer_timeout(ErtsBifTimer* btm){    ASSERT(btm);    erts_smp_btm_rwlock();    if (btm->flags & BTM_FLG_CANCELED) {    /*     * A concurrent cancel is ongoing. Do not send the timeout message,     * but cleanup here since the cancel call-back won't be called.     */#ifndef ERTS_SMP	ASSERT(0);#endif    }    else {	Uint32 rp_locks = ERTS_PROC_LOCKS_MSG_SEND;	Process* rp;	tab_remove(btm);	ASSERT(!erts_get_current_process());	if (btm->flags & BTM_FLG_BYNAME)	    rp = erts_whereis_process(NULL,0,btm->receiver.name,rp_locks,0);	else {	    rp = btm->receiver.proc.ess;	    erts_smp_proc_lock(rp, rp_locks);	    unlink_proc(btm);	    if (ERTS_PROC_IS_EXITING(rp)) {		erts_smp_proc_unlock(rp, rp_locks);		rp = NULL;	    }	}	if (rp) {	    if (!ERTS_PROC_PENDING_EXIT(rp)) {		Eterm message;		ErlHeapFragment *bp;		bp = btm->bp;		btm->bp = NULL; /* Prevent cleanup of message buffer... */		if (!(btm->flags & BTM_FLG_WRAP))		    message = btm->message;		else {#if ERTS_REF_NUMBERS != 3#error "ERTS_REF_NUMBERS changed. Update me..."#endif		    Eterm ref;		    Uint *hp;		    Uint wrap_size = REF_THING_SIZE + 4;		    message = btm->message;#ifndef HEAP_FRAG_ELIM_TEST#ifdef ERTS_SMP		    if (erts_smp_proc_trylock(rp, ERTS_PROC_LOCK_MAIN) == 0) {			rp_locks |= ERTS_PROC_LOCK_MAIN;#endif			if (bp != NULL) {			    erts_link_mbuf_to_proc(rp, bp);			    bp = NULL;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -