github.com/spotify/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/runtime/mfinal.c (about)

     1  // Copyright 2010 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include "runtime.h"
     6  #include "arch_GOARCH.h"
     7  #include "malloc.h"
     8  #include "type.h"
     9  
    10  enum { debug = 0 };
    11  
    12  typedef struct Fin Fin;
    13  struct Fin
    14  {
    15  	FuncVal *fn;
    16  	uintptr nret;
    17  	Type *fint;
    18  	PtrType *ot;
    19  };
    20  
    21  // Finalizer hash table.  Direct hash, linear scan, at most 3/4 full.
    22  // Table size is power of 3 so that hash can be key % max.
    23  // Key[i] == (void*)-1 denotes free but formerly occupied entry
    24  // (doesn't stop the linear scan).
    25  // Key and val are separate tables because the garbage collector
    26  // must be instructed to ignore the pointers in key but follow the
    27  // pointers in val.
    28  typedef struct Fintab Fintab;
    29  struct Fintab
    30  {
    31  	Lock;
    32  	void **key;
    33  	Fin *val;
    34  	int32 nkey;	// number of non-nil entries in key
    35  	int32 ndead;	// number of dead (-1) entries in key
    36  	int32 max;	// size of key, val allocations
    37  };
    38  
    39  #define TABSZ 17
    40  #define TAB(p) (&fintab[((uintptr)(p)>>3)%TABSZ])
    41  
    42  static struct {
    43  	Fintab;
    44  	uint8 pad[CacheLineSize - sizeof(Fintab)];	
    45  } fintab[TABSZ];
    46  
    47  static void
    48  addfintab(Fintab *t, void *k, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot)
    49  {
    50  	int32 i, j;
    51  
    52  	i = (uintptr)k % (uintptr)t->max;
    53  	for(j=0; j<t->max; j++) {
    54  		if(t->key[i] == nil) {
    55  			t->nkey++;
    56  			goto ret;
    57  		}
    58  		if(t->key[i] == (void*)-1) {
    59  			t->ndead--;
    60  			goto ret;
    61  		}
    62  		if(++i == t->max)
    63  			i = 0;
    64  	}
    65  
    66  	// cannot happen - table is known to be non-full
    67  	runtime·throw("finalizer table inconsistent");
    68  
    69  ret:
    70  	t->key[i] = k;
    71  	t->val[i].fn = fn;
    72  	t->val[i].nret = nret;
    73  	t->val[i].fint = fint;
    74  	t->val[i].ot = ot;
    75  }
    76  
    77  static bool
    78  lookfintab(Fintab *t, void *k, bool del, Fin *f)
    79  {
    80  	int32 i, j;
    81  
    82  	if(t->max == 0)
    83  		return false;
    84  	i = (uintptr)k % (uintptr)t->max;
    85  	for(j=0; j<t->max; j++) {
    86  		if(t->key[i] == nil)
    87  			return false;
    88  		if(t->key[i] == k) {
    89  			if(f)
    90  				*f = t->val[i];
    91  			if(del) {
    92  				t->key[i] = (void*)-1;
    93  				t->val[i].fn = nil;
    94  				t->val[i].nret = 0;
    95  				t->val[i].ot = nil;
    96  				t->ndead++;
    97  			}
    98  			return true;
    99  		}
   100  		if(++i == t->max)
   101  			i = 0;
   102  	}
   103  
   104  	// cannot happen - table is known to be non-full
   105  	runtime·throw("finalizer table inconsistent");
   106  	return false;
   107  }
   108  
   109  static void
   110  resizefintab(Fintab *tab)
   111  {
   112  	Fintab newtab;
   113  	void *k;
   114  	int32 i;
   115  
   116  	runtime·memclr((byte*)&newtab, sizeof newtab);
   117  	newtab.max = tab->max;
   118  	if(newtab.max == 0)
   119  		newtab.max = 3*3*3;
   120  	else if(tab->ndead < tab->nkey/2) {
   121  		// grow table if not many dead values.
   122  		// otherwise just rehash into table of same size.
   123  		newtab.max *= 3;
   124  	}
   125  	
   126  	newtab.key = runtime·mallocgc(newtab.max*sizeof newtab.key[0], 0, FlagNoInvokeGC|FlagNoScan);
   127  	newtab.val = runtime·mallocgc(newtab.max*sizeof newtab.val[0], 0, FlagNoInvokeGC);
   128  	
   129  	for(i=0; i<tab->max; i++) {
   130  		k = tab->key[i];
   131  		if(k != nil && k != (void*)-1)
   132  			addfintab(&newtab, k, tab->val[i].fn, tab->val[i].nret, tab->val[i].fint, tab->val[i].ot);
   133  	}
   134  	
   135  	runtime·free(tab->key);
   136  	runtime·free(tab->val);
   137  	
   138  	tab->key = newtab.key;
   139  	tab->val = newtab.val;
   140  	tab->nkey = newtab.nkey;
   141  	tab->ndead = newtab.ndead;
   142  	tab->max = newtab.max;
   143  }
   144  
   145  bool
   146  runtime·addfinalizer(void *p, FuncVal *f, uintptr nret, Type *fint, PtrType *ot)
   147  {
   148  	Fintab *tab;
   149  	byte *base;
   150  	
   151  	if(debug) {
   152  		if(!runtime·mlookup(p, &base, nil, nil) || p != base)
   153  			runtime·throw("addfinalizer on invalid pointer");
   154  	}
   155  	
   156  	tab = TAB(p);
   157  	runtime·lock(tab);
   158  	if(f == nil) {
   159  		lookfintab(tab, p, true, nil);
   160  		runtime·unlock(tab);
   161  		return true;
   162  	}
   163  
   164  	if(lookfintab(tab, p, false, nil)) {
   165  		runtime·unlock(tab);
   166  		return false;
   167  	}
   168  
   169  	if(tab->nkey >= tab->max/2+tab->max/4) {
   170  		// keep table at most 3/4 full:
   171  		// allocate new table and rehash.
   172  		resizefintab(tab);
   173  	}
   174  
   175  	addfintab(tab, p, f, nret, fint, ot);
   176  	runtime·setblockspecial(p, true);
   177  	runtime·unlock(tab);
   178  	return true;
   179  }
   180  
   181  // get finalizer; if del, delete finalizer.
   182  // caller is responsible for updating RefHasFinalizer (special) bit.
   183  bool
   184  runtime·getfinalizer(void *p, bool del, FuncVal **fn, uintptr *nret, Type **fint, PtrType **ot)
   185  {
   186  	Fintab *tab;
   187  	bool res;
   188  	Fin f;
   189  	
   190  	tab = TAB(p);
   191  	runtime·lock(tab);
   192  	res = lookfintab(tab, p, del, &f);
   193  	runtime·unlock(tab);
   194  	if(res==false)
   195  		return false;
   196  	*fn = f.fn;
   197  	*nret = f.nret;
   198  	*fint = f.fint;
   199  	*ot = f.ot;
   200  	return true;
   201  }
   202  
   203  void
   204  runtime·walkfintab(void (*fn)(void*))
   205  {
   206  	void **key;
   207  	void **ekey;
   208  	int32 i;
   209  
   210  	for(i=0; i<TABSZ; i++) {
   211  		runtime·lock(&fintab[i]);
   212  		key = fintab[i].key;
   213  		ekey = key + fintab[i].max;
   214  		for(; key < ekey; key++)
   215  			if(*key != nil && *key != ((void*)-1))
   216  				fn(*key);
   217  		runtime·unlock(&fintab[i]);
   218  	}
   219  }