Skip to content

Commit

Permalink
ddstring: Option to use standard memory allocs
Browse files Browse the repository at this point in the history
ddstrings were being used with libcurl when communicating
with the master server. However, ddstrings were internally
using the memory zone for memory allocs, which is not
thread-safe.

Now there is an option to choose regular memory allocs for
a ddstring_t.
  • Loading branch information
skyjake committed Aug 2, 2011
1 parent df572d3 commit 9d0cbac
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 39 deletions.
13 changes: 9 additions & 4 deletions doomsday/engine/portable/include/m_string.h
Expand Up @@ -33,8 +33,11 @@

typedef struct ddstring_s {
char *str;
size_t length; // String length (no terminating nulls).
size_t size; // Allocated memory (not necessarily string size).
size_t length; // String length (no terminating nulls).
size_t size; // Allocated memory (not necessarily string size).
void (*memFree)(void*);
void* (*memAlloc)(size_t n);
void* (*memCalloc)(size_t n);
} ddstring_t;

// Format checking for Str_Appendf in GCC2
Expand All @@ -44,9 +47,11 @@ typedef struct ddstring_s {
# define PRINTF_F(f,v)
#endif

void Str_Init(ddstring_t *ds);
void Str_Init(ddstring_t *ds); // uses the memory zone
void Str_InitStd(ddstring_t* ds); // uses malloc/free
void Str_Free(ddstring_t *ds);
ddstring_t *Str_New(void);
ddstring_t *Str_New(void);
ddstring_t *Str_NewStd(void);
void Str_Delete(ddstring_t *ds);
void Str_Clear(ddstring_t *ds);
void Str_Reserve(ddstring_t *ds, size_t length);
Expand Down
4 changes: 3 additions & 1 deletion doomsday/engine/portable/src/dd_zone.c
Expand Up @@ -719,7 +719,7 @@ int Z_GetTag(void *ptr)
*/
void *Z_Calloc(size_t size, int tag, void *user)
{
void *ptr = Z_Malloc(size, tag, user);
void *ptr = Z_Malloc(size, tag, user);

memset(ptr, 0, ALIGNED(size));
return ptr;
Expand All @@ -734,6 +734,8 @@ void *Z_Recalloc(void *ptr, size_t n, int callocTag)
void *p;
size_t bsize;

n = ALIGNED(n);

if(ptr) // Has old data.
{
p = Z_Malloc(n, Z_GetTag(ptr), NULL);
Expand Down
135 changes: 104 additions & 31 deletions doomsday/engine/portable/src/m_string.c
Expand Up @@ -26,45 +26,72 @@
* m_string.c: Dynamic Strings
*
* Simple dynamic string management.
* Uses the memory zone for memory allocation.
* Uses either normal mallocs or the memory zone for memory allocation
* (chosen with the Init function).
*/

// HEADER FILES ------------------------------------------------------------

#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "de_base.h"
#include "de_misc.h"

// MACROS ------------------------------------------------------------------

#define MAX_LENGTH 0x4000

// TYPES -------------------------------------------------------------------

// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------

// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------

// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------

// EXTERNAL DATA DECLARATIONS ----------------------------------------------
static void* zoneAlloc(size_t n) {
return Z_Malloc(n, PU_STATIC, 0);
}

// PUBLIC DATA DEFINITIONS -------------------------------------------------
static void* zoneCalloc(size_t n) {
return Z_Calloc(n, PU_STATIC, 0);
}

// PRIVATE DATA DEFINITIONS ------------------------------------------------
static void* stdCalloc(size_t n) {
return calloc(1, n);
}

// CODE --------------------------------------------------------------------
static void Str_AutoInit(ddstring_t* ds)
{
if(!ds->memFree && !ds->memAlloc && !ds->memCalloc)
{
// If the memory model is unspecified, default to the standard,
// it is safer for threading.
ds->memFree = free;
ds->memAlloc = malloc;
ds->memCalloc = stdCalloc;
}
assert(ds->memFree);
assert(ds->memAlloc);
assert(ds->memCalloc);
}

/**
* Call this for uninitialized strings. Global variables are
* automatically cleared, so they don't need initialization.
* The string will use the memory zone.
*/
void Str_Init(ddstring_t *ds)
{
memset(ds, 0, sizeof(*ds));

// Init the memory management.
ds->memFree = Z_Free;
ds->memAlloc = zoneAlloc;
ds->memCalloc = zoneCalloc;
}

/**
* The string will use standard memory allocation.
*/
void Str_InitStd(ddstring_t *ds)
{
memset(ds, 0, sizeof(*ds));

// Init the memory management.
ds->memFree = free;
ds->memAlloc = malloc;
ds->memCalloc = stdCalloc;
}

/**
Expand All @@ -73,12 +100,18 @@ void Str_Init(ddstring_t *ds)
*/
void Str_Free(ddstring_t *ds)
{
Str_AutoInit(ds);

if(ds->size)
{
// The string has memory allocated, free it.
Z_Free(ds->str);
ds->memFree(ds->str);
}
memset(ds, 0, sizeof(*ds));

// Memory model left unchanged.
ds->length = 0;
ds->size = 0;
ds->str = 0;
}

/**
Expand All @@ -91,7 +124,16 @@ void Str_Free(ddstring_t *ds)
*/
ddstring_t *Str_New(void)
{
return M_Calloc(sizeof(ddstring_t));
ddstring_t* str = (ddstring_t*) M_Calloc(sizeof(ddstring_t));
Str_Init(str);
return str;
}

ddstring_t *Str_NewStd(void)
{
ddstring_t* str = (ddstring_t*) M_Calloc(sizeof(ddstring_t));
Str_InitStd(str);
return str;
}

/**
Expand Down Expand Up @@ -129,6 +171,8 @@ void Str_Alloc(ddstring_t *ds, size_t for_length, int preserve)
if(ds->size >= for_length)
return; // We're OK.

Str_AutoInit(ds);

// Already some memory allocated?
if(ds->size)
old_data = true;
Expand All @@ -137,14 +181,19 @@ void Str_Alloc(ddstring_t *ds, size_t for_length, int preserve)

while(ds->size < for_length)
ds->size *= 2;
buf = Z_Calloc(ds->size, PU_STATIC, 0);

assert(ds->memCalloc);
buf = ds->memCalloc(ds->size);

if(preserve && ds->str)
strncpy(buf, ds->str, ds->size - 1);

// Replace the old string with the new buffer.
if(old_data)
Z_Free(ds->str);
{
assert(ds->memFree);
ds->memFree(ds->str);
}
ds->str = buf;
}

Expand All @@ -155,24 +204,35 @@ void Str_Reserve(ddstring_t *ds, size_t length)

void Str_Set(ddstring_t *ds, const char *text)
{
size_t incoming = strlen(text);
size_t incoming = strlen(text);
char* copied = M_Malloc(incoming + 1); // take a copy in case text points to (a part of) ds->str

strcpy(copied, text);
Str_Alloc(ds, incoming, false);
strcpy(ds->str, text);
strcpy(ds->str, copied);
ds->length = incoming;
M_Free(copied);
}

void Str_Append(ddstring_t *ds, const char *append_text)
{
size_t incoming = strlen(append_text);
size_t incoming = strlen(append_text);
char* copied;

// Don't allow extremely long strings.
if(ds->length > MAX_LENGTH)
return;

// Take a copy in case append_text points to (a part of) ds->str, which may be invalidated
// by Str_Alloc.
copied = M_Malloc(incoming + 1);
strcpy(copied, append_text);

Str_Alloc(ds, ds->length + incoming, true);
strcpy(ds->str + ds->length, append_text);
strcpy(ds->str + ds->length, copied);
ds->length += incoming;

M_Free(copied);
}

void Str_AppendChar(ddstring_t* ds, char ch)
Expand All @@ -186,7 +246,7 @@ void Str_AppendChar(ddstring_t* ds, char ch)
*/
void Str_Appendf(ddstring_t *ds, const char *format, ...)
{
char buf[1024];
char buf[1024];
va_list args;

// Print the message into the buffer.
Expand All @@ -201,29 +261,41 @@ void Str_Appendf(ddstring_t *ds, const char *format, ...)
*/
void Str_PartAppend(ddstring_t *dest, const char *src, int start, size_t count)
{
char* copied = M_Malloc(count);

memcpy(copied, src + start, count);

Str_Alloc(dest, dest->length + count + 1, true);
memcpy(dest->str + dest->length, src + start, count);
memcpy(dest->str + dest->length, copied, count);
dest->length += count;

// Terminate the appended part.
dest->str[dest->length] = 0;

M_Free(copied);
}

/**
* Prepend is not even a word, is it? It should be 'prefix'?
*/
void Str_Prepend(ddstring_t *ds, const char *prepend_text)
{
size_t incoming = strlen(prepend_text);
size_t incoming = strlen(prepend_text);
char* copied;

// Don't allow extremely long strings.
if(ds->length > MAX_LENGTH)
return;

copied = M_Malloc(incoming);
memcpy(copied, prepend_text, incoming);

Str_Alloc(ds, ds->length + incoming, true);
memmove(ds->str + incoming, ds->str, ds->length + 1);
memcpy(ds->str, prepend_text, incoming);
memcpy(ds->str, copied, incoming);
ds->length += incoming;

M_Free(copied);
}

/**
Expand Down Expand Up @@ -252,7 +324,8 @@ void Str_Copy(ddstring_t *dest, ddstring_t *src)
Str_Free(dest);
dest->size = src->size;
dest->length = src->length;
dest->str = Z_Malloc(src->size, PU_STATIC, 0);
assert(dest->memAlloc);
dest->str = dest->memAlloc(src->size);
memcpy(dest->str, src->str, src->size);
}

Expand Down
6 changes: 3 additions & 3 deletions doomsday/engine/portable/src/sys_master.c
Expand Up @@ -198,7 +198,7 @@ static int N_MasterParseResponse(ddstring_t *msg)
const char *pos;
serverinfo_t *info = NULL;

Str_Init(&line);
Str_InitStd(&line);

// Clear the list of servers.
N_MasterClearList();
Expand Down Expand Up @@ -257,7 +257,7 @@ static int C_DECL N_MasterSendRequest(void *parm)
N_MasterGetUrl(masterUrl);
strcat(masterUrl, "?list");

Str_Init(&response);
Str_InitStd(&response);

// Prepare the curl session for our HTTP GET request.
session = curl_easy_init();
Expand Down Expand Up @@ -324,7 +324,7 @@ static int C_DECL N_MasterSendAnnouncement(void *parm)
N_MasterGetUrl(masterUrl);

// Convert the serverinfo into plain text.
Str_Init(&msg);
Str_InitStd(&msg);
Sv_InfoToString(info, &msg);
// Free the serverinfo, it's no longer needed.
M_Free(info);
Expand Down

0 comments on commit 9d0cbac

Please sign in to comment.