pike.git / src / stralloc.c

version» Context lines:

pike.git/src/stralloc.c:19:      #include <errno.h>   #include <float.h>   #include <ctype.h>   #include <math.h>      #ifndef HUGE   #define HUGE HUGE_VAL   #endif /*!HUGE*/    - RCSID("$Id: stralloc.c,v 1.120 2001/03/29 20:23:32 grubba Exp $"); + RCSID("$Id: stralloc.c,v 1.121 2001/03/30 09:09:09 hubbe Exp $");    -  + #if PIKE_RUN_UNLOCKED + static PIKE_MUTEX_T *bucket_locks; +  + #define LOCK_BUCKET(HVAL) do { \ +  size_t hval__=(HVAL); \ +  PIKE_MUTEX_T *bucket_lock; \ +  while(1) \ +  { \ +  bucket_lock=bucket_locks + (hval__ % htable_size); \ +  mt_lock(bucket_lock); \ +  if(bucket_lock == bucket_locks + (hval__ % htable_size)) \ +  break; \ +  mt_unlock(bucket_lock); \ +  } \ + }while(0) +  + #define UNLOCK_BUCKET(HVAL) do { \ +  size_t hval__=(HVAL); \ +  mt_unlock(bucket_locks + ( hval__ % htable_size )); \ + }while(0) +  + #else + #define LOCK_BUCKET(HVAL) + #define UNLOCK_BUCKET(HVAL) + #endif +    #define BEGIN_HASH_SIZE 997   #define MAX_AVG_LINK_LENGTH 3      /* Experimental dynamic hash length */   #ifndef HASH_PREFIX   static unsigned int HASH_PREFIX=64;   static unsigned int need_more_hash_prefix=0;   #endif      unsigned INT32 htable_size=0;
pike.git/src/stralloc.c:245:      static void locate_problem(int (*isproblem)(struct pike_string *))   {    unsigned INT32 e;    struct pike_string *s;    DM(struct memhdr *yes=alloc_memhdr());    DM(struct memhdr *no=alloc_memhdr());       for(e=0;e<htable_size;e++)    { +  LOCK_BUCKET(e);    for(s=base_table[e];s;s=s->next)    {    if(isproblem(s))    {    fprintf(stderr,"***Guilty string:\n");    debug_dump_pike_string(s, 70);    DM(add_marks_to_memhdr(yes,s));    }else{    DM(add_marks_to_memhdr(no,s));    }    } -  +  UNLOCK_BUCKET(e);    }       DM(fprintf(stderr,"Plausible problem location(s):\n"));    DM(dump_memhdr_locations(yes,0,0));       DM(fprintf(stderr,"More Plausible problem location(s):\n"));    DM(dump_memhdr_locations(yes,no,0));   }      static int has_zero_refs(struct pike_string *s)
pike.git/src/stralloc.c:293:    */   static INLINE struct pike_string *internal_findstring(const char *s,    ptrdiff_t len,    int size_shift,    ptrdiff_t hval)   {    struct pike_string *curr,**prev, **base;   #ifndef HASH_PREFIX    unsigned int depth=0;   #endif -  size_t h=hval % htable_size; +  size_t h; +  LOCK_BUCKET(hval); +  h=hval % htable_size;    for(base = prev = base_table + h;( curr=*prev ); prev=&curr->next)    {   #ifdef PIKE_DEBUG    if(curr->refs<1)    {    debug_dump_pike_string(curr, 70);    locate_problem(has_zero_refs);    fatal("String with no references.\n");    }   #endif
pike.git/src/stralloc.c:315:       if (hval == curr->hval &&    len==curr->len &&    size_shift==curr->size_shift &&    ( curr->str == s ||    !MEMCMP(curr->str, s,len<<size_shift))) /* found it */    {    *prev = curr->next;    curr->next = *base;    *base = curr; +  UNLOCK_BUCKET(hval);    return curr; /* pointer to string */    }   #ifndef HASH_PREFIX    depth++;   #endif    }   #ifndef HASH_PREFIX    /* These heuruistics might require tuning! /Hubbe */    if((depth > HASH_PREFIX) && (HASH_PREFIX < (size_t)len))    {    need_more_hash_prefix++;   /* fprintf(stderr,"depth=%d num_strings=%d need_more_hash_prefix=%d HASH_PREFIX=%d\n",depth,num_strings,need_more_hash_prefix,HASH_PREFIX); */    }else{    if(need_more_hash_prefix)    need_more_hash_prefix--;    }   #endif -  +  UNLOCK_BUCKET(hval);    return 0; /* not found */   }      PMOD_EXPORT struct pike_string *binary_findstring(const char *foo, ptrdiff_t l)   {    return internal_findstring(foo, l, 0, StrHash(foo,l));   }      PMOD_EXPORT struct pike_string *findstring(const char *foo)   {
pike.git/src/stralloc.c:387:   static void rehash_string_backwards(struct pike_string *s)   {    ptrdiff_t h;    if(!s) return;    rehash_string_backwards(s->next);    h = s->hval % htable_size;    s->next=base_table[h];    base_table[h]=s;   }    - static void rehash(void) + static void stralloc_rehash(void)   {    int h,old;    struct pike_string **old_base;    -  + #ifdef PIKE_RUN_UNLOCKED +  int new_htable_size; +  PIKE_MUTEX_T *old_locks; +  PIKE_MUTEX_T *new_locks; +     old=htable_size;    old_base=base_table;    -  +  LOCK_BUCKET(0); +  if(old != htable_size) +  { +  /* Someone got here before us */ +  UNLOCK_BUCKET(0); +  return; +  } +  +  new_htable_size=hashprimes[++hashprimes_entry]; +  +  /* Now that we have bucket zero, the hash table +  * cannot change, go ahead and lock ALL buckets. +  * NOTE: bucket zero is already locked +  */ +  for(h=1;h<old;h++) LOCK_BUCKET(h); +  new_locks=(PIKE_MUTEX_T *)xalloc(sizeof(PIKE_MUTEX_T)*new_htable_size); +  for(h=0;h<new_htable_size;h++) +  { +  mt_init(new_locks + h); +  mt_lock(new_locks + h); +  } +  old_locks=bucket_locks; +  bucket_locks=new_locks; +  htable_size=new_htable_size; + #else +  old=htable_size; +  old_base=base_table; +     htable_size=hashprimes[++hashprimes_entry]; -  + #endif +     base_table=(struct pike_string **)xalloc(sizeof(struct pike_string *)*htable_size);    MEMSET((char *)base_table,0,sizeof(struct pike_string *)*htable_size);       for(h=0;h<old;h++)    rehash_string_backwards(old_base[h]);       if(old_base)    free((char *)old_base); -  +  + #ifdef PIKE_RUN_UNLOCKED +  for(h=0;h<old;h++) mt_unlock(old_locks + h); +  for(h=0;h<htable_size;h++) mt_unlock(new_locks + h); +  +  +  /* This loop tries to make sure that nobody is still waiting +  * for the old locks. I'm not sure if it actually works 100% of +  * the time though... /Hubbe +  */ +  for(h=0;h<old;h++) +  { +  mt_lock(old_locks + h); +  mt_unlock(old_locks + h); +  mt_destroy(old_locks+h);    } -  +  free((char *)old_locks); + #endif + }      /* Allocation of strings */      /* Allocate some fixed string sizes with BLOCK_ALLOC. */      /* Use the BLOCK_ALLOC() stuff for short strings */      #define SHORT_STRING_BLOCK 256   #define SHORT_STRING_THRESHOLD 16   
pike.git/src/stralloc.c:487:    }    t->str[len]=0;    t->len=len;    t->size_shift=0;    return t;   }      static void link_pike_string(struct pike_string *s, size_t hval)   {    size_t h; +  LOCK_BUCKET(hval);    h=hval % htable_size;    s->refs = 0;    s->next = base_table[h];    base_table[h] = s;    s->hval=hval;    num_strings++; -  +  UNLOCK_BUCKET(hval); +     if(num_strings > MAX_AVG_LINK_LENGTH * htable_size) -  rehash(); +  stralloc_rehash();      #ifndef HASH_PREFIX    /* These heuruistics might require tuning! /Hubbe */    if(need_more_hash_prefix > ( htable_size >> 4))    {    /* This could in theory have a pretty ugly complexity */    /* /Hubbe    */       need_more_hash_prefix=0;
pike.git/src/stralloc.c:794:   {    INT32 len;    for(len=0;str[len];len++);    return debug_make_shared_binary_string2(str,len);   }      /*** Free strings ***/      PMOD_EXPORT void unlink_pike_string(struct pike_string *s)   { -  size_t h = s->hval % htable_size; +  size_t h; +  LOCK_BUCKET(s->hval); +  h= s->hval % htable_size;    propagate_shared_string(s,h);    base_table[h]=s->next;   #ifdef PIKE_DEBUG    s->next=(struct pike_string *)(ptrdiff_t)-1;   #endif    num_strings--; -  +  UNLOCK_BUCKET(s->hval);   }      PMOD_EXPORT void do_free_string(struct pike_string *s)   {    if (s)    free_string(s);   }      PMOD_EXPORT void do_really_free_string(struct pike_string *s)   {
pike.git/src/stralloc.c:875:    {    int allocd_strings=0;    int allocd_bytes=0;    int num_distinct_strings=0;    int bytes_distinct_strings=0;    ptrdiff_t overhead_bytes = 0;    unsigned INT32 e;    struct pike_string *p;    for(e=0;e<htable_size;e++)    { +  LOCK_BUCKET(e);    for(p=base_table[e];p;p=p->next)    {    num_distinct_strings++;    bytes_distinct_strings+=DO_ALIGN(p->len,sizeof(void *));    allocd_strings+=p->refs;    allocd_bytes+=p->refs*DO_ALIGN(p->len+3,sizeof(void *));    } -  +  UNLOCK_BUCKET(e);    }    overhead_bytes=(sizeof(struct pike_string)-1)*num_distinct_strings;    my_strcat("\nShared string hash table:\n");    my_strcat("-------------------------\t Strings Bytes\n");       sprintf(b,"Total asked for\t\t\t%8ld %8ld\n",    (long)allocd_strings, (long)allocd_bytes);    my_strcat(b);    sprintf(b,"Strings malloced\t\t%8ld %8ld + %ld overhead\n",    (long)num_distinct_strings,
pike.git/src/stralloc.c:938: Inside #if defined(PIKE_DEBUG)
  }      PMOD_EXPORT void verify_shared_strings_tables(void)   {    unsigned INT32 e, h, num=0;    struct pike_string *s;       for(e=0;e<htable_size;e++)    {    h=0; +  LOCK_BUCKET(e);    for(s=base_table[e];s;s=s->next)    {    num++;    h++;    if(s->len < 0)    fatal("Shared string shorter than zero bytes.\n");       if(s->refs <= 0)    {    locate_problem(has_zero_refs);
pike.git/src/stralloc.c:975: Inside #if defined(PIKE_DEBUG)
      if(h>10000)    {    struct pike_string *s2;    for(s2=s;s2;s2=s2->next)    if(s2 == s)    fatal("Shared string table is cyclic.\n");    h=0;    }    } +  UNLOCK_BUCKET(e);    }    if(num != num_strings)    fatal("Num strings is wrong %d!=%d\n",num,num_strings);   }      PMOD_EXPORT int safe_debug_findstring(struct pike_string *foo)   {    unsigned INT32 e;    if(!base_table) return 0;    for(e=0;e<htable_size;e++)    {    struct pike_string *p; -  +  LOCK_BUCKET(e);    for(p=base_table[e];p;p=p->next) -  if(p==foo) return 1; +  { +  if(p==foo) +  { +  UNLOCK_BUCKET(e); +  return 1;    } -  +  } +  UNLOCK_BUCKET(e); +  }    return 0;   }      PMOD_EXPORT struct pike_string *debug_findstring(const struct pike_string *foo)   {    struct pike_string *tmp;    tmp=propagate_shared_string(foo, foo->hval % htable_size);      #if 0    if(!tmp)    {    unsigned INT32 e;    struct pike_string *tmp2;    fprintf(stderr,"String %p %ld %ld %s\n",    foo,    (long)foo->hval,    (long)foo->len,    foo->str);    -  +  LOCK_BUCKET(foo->hval);    fprintf(stderr,"------ %p %ld\n",    base_table[foo->hval %htable_size],    foo->hval);    for(tmp2=base_table[foo->hval % htable_size];tmp2;tmp2=tmp2->next)    {    if(tmp2 == tmp)    fprintf(stderr,"!!%p!!->",tmp2);    else    fprintf(stderr,"%p->",tmp2);    }    fprintf(stderr,"0\n"); -  +  UNLOCK_BUCKET(foo->hval);       for(e=0;e<htable_size;e++)    { -  +  LOCK_BUCKET(e);    for(tmp2=base_table[e];tmp2;tmp2=tmp2->next)    {    if(tmp2 == tmp)    fprintf(stderr,"String found in hashbin %ld (not %ld)\n",    (long)e,    (long)(foo->hval % htable_size));    } -  +  UNLOCK_BUCKET(e);    }    }   #endif    return tmp;   }      PMOD_EXPORT void debug_dump_pike_string(struct pike_string *s, INT32 max)   {    INT32 e;    fprintf(stderr,"0x%p: %ld refs, len=%ld, size_shift=%d, hval=%lux (%lx)\n",
pike.git/src/stralloc.c:1079: Inside #if defined(PIKE_DEBUG)
   fprintf(stderr,"...\n");    else    fprintf(stderr,"\"\n");   }      void dump_stralloc_strings(void)   {    unsigned INT32 e;    struct pike_string *p;    for(e=0;e<htable_size;e++) +  { +  LOCK_BUCKET(e);    for(p=base_table[e];p;p=p->next)    debug_dump_pike_string(p, 70); -  +  UNLOCK_BUCKET(e);    } -  + }      #endif         /*** String compare functions ***/      /* does not take locale into account */   PMOD_EXPORT int low_quick_binary_strcmp(char *a, ptrdiff_t alen,    char *b, ptrdiff_t blen)   {
pike.git/src/stralloc.c:1643:    }    generic_memcpy(r,MKPCHARP(s,str->size_shift),(end-s)>>str->size_shift);       mojt.vtab->freeme(mojt.data);    return end_shared_string(ret);   }      /*** init/exit memory ***/   void init_shared_string_table(void)   { - #ifdef PIKE_RUN_UNLOCKED -  mt_init(&stralloc_mutex); - #endif +     init_short_pike_string0_blocks();    init_short_pike_string1_blocks();    init_short_pike_string2_blocks();    for(hashprimes_entry=0;hashprimes[hashprimes_entry]<BEGIN_HASH_SIZE;hashprimes_entry++);    htable_size=hashprimes[hashprimes_entry];    base_table=(struct pike_string **)xalloc(sizeof(struct pike_string *)*htable_size);    MEMSET((char *)base_table,0,sizeof(struct pike_string *)*htable_size); -  + #ifdef PIKE_RUN_UNLOCKED +  { +  int h; +  bucket_locks=(PIKE_MUTEX_T *)xalloc(sizeof(PIKE_MUTEX_T)*htable_size); +  for(h=0;h<htable_size;h++) mt_init(bucket_locks + h);    } -  + #endif + }      #ifdef DEBUG_MALLOC   struct shared_string_location *all_shared_string_locations;   #endif         void cleanup_shared_string_table(void)   {    unsigned INT32 e;    struct pike_string *s,*next;
pike.git/src/stralloc.c:1688: Inside #if defined(PIKE_DEBUG) && defined(DEBUG_MALLOC)
   if(num)    {    fprintf(stderr,"Strings left: %d (%d bytes) (zapped)\n",num,size);    dump_stralloc_strings();    }    }   #endif       for(e=0;e<htable_size;e++)    { +  LOCK_BUCKET(e);    for(s=base_table[e];s;s=next)    {    next=s->next;   #ifdef REALLY_FREE    really_free_pike_string(s);   #else    s->next=0;   #endif    }    base_table[e]=0; -  +  UNLOCK_BUCKET(e);    }    free((char *)base_table);    base_table=0;    num_strings=0;      #ifdef DEBUG_MALLOC    free_all_short_pike_string0_blocks();    free_all_short_pike_string1_blocks();    free_all_short_pike_string2_blocks();   #endif /* DEBUG_MALLOC */
pike.git/src/stralloc.c:1722:    unsigned INT32 e, num_=0, size_=0;    if(!base_table)    {    *num=*size=0;    return;    }    size_+=htable_size * sizeof(struct pike_string *);    for(e=0;e<htable_size;e++)    {    struct pike_string *p; +  LOCK_BUCKET(e);    for(p=base_table[e];p;p=p->next)    {    num_++;    size_+=sizeof(struct pike_string)+(p->len<<p->size_shift);    } -  +  UNLOCK_BUCKET(e);    }   #ifdef PIKE_DEBUG    if(num_strings != num_)    fatal("Num strings is wrong! %d!=%d.\n",num_strings, num_);   #endif    num[0]=num_;    size[0]=size_;   }      #ifdef PIKE_DEBUG