char *_str_dup(const char *str, const char *caller) { BufEntry *ptr; int len; int rlen; char *str_new; ssm_dup_count++; ssm_recent_loops=0; if (!str || !*str) return &str_empty[0]; if (str > string_space && str < top_string) { ptr = (BufEntry *) (str - HEADER_SIZE); if (ptr->usage <= 0) { bugf("str_dup: invalid string from %s: %20.20s", caller, str); ptr->usage=0; /* make it valid again */ } ptr->usage++; return (char *) str; } rlen = len = (int) strlen(str) + 1; /* * Round up to machine dependant address size. * Don't remove this, because when the BufEntry struct is overlaid * the struct must be aligned correctly. */ if ((len + HEADER_SIZE) & addrSizeMask) len += addrTypeSize - ((len + HEADER_SIZE) & addrSizeMask); RETRY: for (ptr = ssm_buf_free; ptr; ptr = ptr->next) { ssm_recent_loops++; ssm_loops++; if (ptr->usage == 0 && ptr->size >= len) break; } if (ptr) ptr->usage = 1; if (!ptr) { if (numFree > 1) numFree++; if (numFree >= MAX_FREE) { int merges; log_f("SSM: Attempting to optimize shared string heap."); merges = defrag_heap(); /* goto is fine because defrag will return 0 next time */ if (merges) goto RETRY; } /* A one time toggle just for bugging purposes */ if (!Full) { bugf("SSM: The shared string heap is full!"); Full = 1; } str_new = (char *) malloc(rlen); strcpy(str_new, str); sOverFlowString += rlen; nOverFlowString++; if (sOverFlowString > hwOverFlow) hwOverFlow=sOverFlowString; return str_new; } /* If there is at least header size excess break it up */ else if (ptr->size - len >= (HEADER_SIZE+8)) { BufEntry *temp; /* WARNING! - DONT REMOVE THE CASTS BELOW! - Fusion */ temp = (BufEntry *) ((char *) ptr + HEADER_SIZE + len); temp->size = ptr->size - (len + HEADER_SIZE); temp->next = ptr->next; temp->usage = 0; ptr->size = len; ptr->next = temp; ssm_buf_free = temp; } else { if (ptr != ssm_buf_free) ssm_buf_free->usage--; /* buf_free was skipped */ /* spec: don't start from the start of the heap again! */ for ( ; ssm_buf_free; ssm_buf_free = ssm_buf_free->next) { ssm_loops++; ssm_recent_loops++; if (ssm_buf_free->usage == 0) break; } } str_new = (char *) &ptr->buf[0]; strcpy(str_new, str); ptr->caller=caller; nAllocString++; sAllocString += ptr->size + HEADER_SIZE; return str_new; }
/* * Dup a string into shared space. If string exists, the usage count * gets incremented and the reference is returned. If the string does * not exist in heap, space is allocated and usage is 1. * This is a linked list first fit algorithm, so strings can be * freed. Upon bootup, there is a seperate hash table constructed in order * to do crunching, then the table is destroyed. */ char *str_dup( const char *str ) { BufEntry *ptr; char *str_new; int len; int rlen; if( !str || !*str ) return &str_empty[0]; // See if we've already got the string we're looking for // if so, return a pointer to that string. if( str > string_space && str < top_string ) { ptr = (BufEntry *)( str - HEADER_SIZE ); if( ptr->usage <= 0 ) { bug( "str_dup : invalid str", 0 ); bug( str, 0 ); } ptr->usage++; return (char *)str; } // Rlen, for required length - we need an extra char for the '\0'. rlen = len = (int)strlen( str ) + 1; // Round up to machine dependant address size. // Don't remove this, because when the BufEntry struct is overlaid // the struct must be aligned correctly. if( ( len + HEADER_SIZE ) & addrSizeMask ) len += addrTypeSize - ( ( len + HEADER_SIZE ) & addrSizeMask ); // Do we have room in the shared string buffer? if( ssm_buf_free ) { RETRY: for( ptr = ssm_buf_free; ptr; ptr = ptr->next ) if( ptr->usage == 0 && ptr->size >= len ) break; // If we didn't find a large enough hunk available in the open space, // try to call defrag_heap() to compress the space in the hopes we'll // have room for our string once we're compressed things. if( !ptr ) { if( numFree >= MAX_FREE ) { int merges; bug( "[SSM] Attempting to optimize shared string heap.", 0 ); merges = defrag_heap(); // goto is fine because defrag will return 0 next time if( merges ) goto RETRY; } // I guess it's just too large for our heap. It gets to sleep in the yard. str_new = (char *)malloc( rlen ); strcpy( str_new, str ); sOverFlowString += rlen; nOverFlowString++; return str_new; } // We found a place to put our string. // If there is at least header size excess break it up else if( ptr->size - len >= HEADER_SIZE ) { BufEntry *temp; // WARNING! - DONT REMOVE THE CASTS BELOW! - Fusion temp = (BufEntry*)( (char *)ptr + HEADER_SIZE + len ); temp->size = ptr->size - ( len + HEADER_SIZE ); temp->next = ptr->next; temp->usage = 0; ptr->size = len; ptr->next = temp; ptr->usage = 1; ssm_buf_free = temp; } else { ptr->usage = 1; if( ptr != ssm_buf_free ) ssm_buf_free->usage--; // buf_free was skipped for( ssm_buf_free = ssm_buf_head; ssm_buf_free; ssm_buf_free = ssm_buf_free->next ) if( ssm_buf_free->usage == 0 ) break; } str_new = (char *)&ptr->buf[0]; strcpy( str_new, str ); nAllocString++; sAllocString += ptr->size + HEADER_SIZE; } else { // A one time toggle just for bugging purposes if( !Full ) { bug( "[SSM] The shared string heap is full!", 0 ); Full = 1; } // And we let our string sleep in the yard. str_new = (char *)malloc( rlen ); strcpy( str_new, str ); sOverFlowString += rlen; nOverFlowString++; } return str_new; }
/* * Dup a string into shared space. If string exists, the usage count * gets incremented and the reference is returned. If the string does * not exist in heap, space is allocated and usage is 1. * This is a linked list first fit algorithm, so strings can be * freed. Upon bootup, there is a seperate hash table constructed in order * to do crunching, then the table is destroyed. */ char *str_dup( const char *str ) { BufEntry *ptr; char *str_new; int len; int rlen; if( !str || !*str ) return &str_empty[0]; if( str > string_space && str < top_string ) { ptr = (BufEntry *)( str - HEADER_SIZE ); if( ptr->usage <= 0 ) { bug( "str_dup : invalid str", 0 ); bug( str, 0 ); } ptr->usage++; return (char *)str; } rlen = len = (int)strlen( str ) + 1; /* * Round up to machine dependant address size. * Don't remove this, because when the BufEntry struct is overlaid * the struct must be aligned correctly. */ if( ( len + HEADER_SIZE ) & addrSizeMask ) len += addrTypeSize - ( ( len + HEADER_SIZE ) & addrSizeMask ); if( ssm_buf_free ) { RETRY: for( ptr = ssm_buf_free; ptr; ptr = ptr->next ) if( ptr->usage == 0 && ptr->size >= len ) break; if( !ptr ) { if( numFree >= MAX_FREE ) { int merges; bug( "[SSM] Attempting to optimize shared string heap.", 0 ); merges = defrag_heap(); /* goto is fine because defrag will return 0 next time */ if( merges ) goto RETRY; } str_new = (char *)malloc( rlen ); strcpy( str_new, str ); sOverFlowString += rlen; nOverFlowString++; return str_new; } /* If there is at least header size excess break it up */ else if( ptr->size - len >= HEADER_SIZE ) { BufEntry *temp; /* WARNING! - DONT REMOVE THE CASTS BELOW! - Fusion */ temp = (BufEntry*)( (char *)ptr + HEADER_SIZE + len ); temp->size = ptr->size - ( len + HEADER_SIZE ); temp->next = ptr->next; temp->usage = 0; ptr->size = len; ptr->next = temp; ptr->usage = 1; ssm_buf_free = temp; } else { ptr->usage = 1; if( ptr != ssm_buf_free ) ssm_buf_free->usage--; /* buf_free was skipped */ for( ssm_buf_free = ssm_buf_head; ssm_buf_free; ssm_buf_free = ssm_buf_free->next ) if( ssm_buf_free->usage == 0 ) break; } str_new = (char *)&ptr->buf[0]; strcpy( str_new, str ); nAllocString++; sAllocString += ptr->size + HEADER_SIZE; } else { /* A one time toggle just for bugging purposes */ if( !Full ) { bug( "[SSM] The shared string heap is full!", 0 ); Full = 1; } str_new = (char *)malloc( rlen ); strcpy( str_new, str ); sOverFlowString += rlen; nOverFlowString++; } return str_new; }