[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Patch: Thread safe obstack
From: |
Herbert Euler |
Subject: |
Patch: Thread safe obstack |
Date: |
Sun, 26 Aug 2007 14:59:47 +0800 |
I have trouble using obstacks with my threaded server, since obstack's
error handling is not thread safe. It provides a user defined
function `obstack_alloc_failed_handler' to signal errors when
allocation fails, and this function can call longjmp instead of
exiting. But I can only call longjmp with a global jmp_buf, since
this function is called with no arguments.
Below is my patch to obstack to give it a chance calling the error
handling function with user provided data, so that obstack can be used
in a thread safe way.
Hope it useful.
Regards,
Guanpeng Xu
2007-08-26 Guanpeng Xu <address@hidden>
* lib/obstack.c (_obstack_newchunk): Call
`obstack_alloc_failed_handler' with user data when thread safe
required.
(_obstack_begin, _obstack_begin_1): Likewise, and add an argument
to thread safe version.
(__attribute__): Add an argument to thread safe version.
* lib/obstack.h (struct obstack): New member `user_data' for
thread safe obstack.
(obstack_alloc_failed_handler): Declared a different prototype for
thread safe obstack.
(set_obstack_user_data, obstack_user_data)
(obstack_init_with_user_data): New macros for thread safe obstack.
(obstack_init, obstack_begin, obstack_specify_allocation)
(obstack_specify_allocation_with_arg): Created thread safe obstack
version.
*** obstack.h.~1.33.~ Mon Jul 23 09:59:03 2007
--- obstack.h Sun Aug 26 14:40:30 2007
***************
*** 160,165 ****
--- 160,171 ----
void *tempptr;
} temp; /* Temporary for some macros. */
int alignment_mask; /* Mask of alignment for each object. */
+ #ifdef OBSTACK_THREAD_SAFE
+ void *user_data; /* The user data is for calling
+ obstack_alloc_failed_handler with
+ user-defined data, to make obstack
+ thread safe. */
+ #endif /* OBSTACK_THREAD_SAFE */
/* These prototypes vary based on `use_extra_arg', and we use
casts to the prototypeless function type in all assignments,
but having prototypes here quiets -Wstrict-prototypes. */
***************
*** 179,189 ****
--- 185,203 ----
/* Declare the external functions we use; they are in obstack.c. */
extern void _obstack_newchunk (struct obstack *, int);
+ #ifdef OBSTACK_THREAD_SAFE
+ extern int _obstack_begin (struct obstack *, int, int,
+ void *(*) (long), void (*) (void *), void *);
+ extern int _obstack_begin_1 (struct obstack *, int, int,
+ void *(*) (void *, long),
+ void (*) (void *, void *), void *, void *);
+ #else
extern int _obstack_begin (struct obstack *, int, int,
void *(*) (long), void (*) (void *));
extern int _obstack_begin_1 (struct obstack *, int, int,
void *(*) (void *, long),
void (*) (void *, void *), void *);
+ #endif
extern int _obstack_memory_used (struct obstack *);
/* The default name of the function for freeing a chunk is 'obstack_free',
***************
*** 198,204 ****
--- 212,222 ----
more memory. This can be set to a user defined function which
should either abort gracefully or use longjump - but shouldn't
return. The default action is to print a message and abort. */
+ #ifdef OBSTACK_THREAD_SAFE
+ extern void (*obstack_alloc_failed_handler) (void *);
+ #else
extern void (*obstack_alloc_failed_handler) (void);
+ #endif
/* Exit value used when `print_and_abort' is used. */
extern int obstack_exit_failure;
***************
*** 222,227 ****
--- 240,282 ----
#define obstack_alignment_mask(h) ((h)->alignment_mask)
/* To prevent prototype warnings provide complete argument list. */
+ #ifdef OBSTACK_THREAD_SAFE
+
+ #define set_obstack_user_data(h, ud) ((h)->user_data = (ud))
+
+ #define obstack_user_data(h) ((h)->user_data + 0)
+
+ #define obstack_init_with_user_data(h, user_data) \
+ _obstack_begin ((h), 0, 0, \
+ (void *(*) (long)) obstack_chunk_alloc, \
+ (void (*) (void *)) obstack_chunk_free, \
+ (user_data))
+
+ #define obstack_init(h) obstack_init_with_user_data ((h), NULL)
+
+ /* The following three macros must be called with H that contains no
+ side effects. */
+
+ #define obstack_begin(h, size) \
+ _obstack_begin ((h), (size), 0, \
+ (void *(*) (long)) obstack_chunk_alloc, \
+ (void (*) (void *)) obstack_chunk_free, \
+ (h)->user_data)
+
+ #define obstack_specify_allocation(h, size, alignment, chunkfun, freefun)
\
+ _obstack_begin ((h), (size), (alignment), \
+ (void *(*) (long)) (chunkfun), \
+ (void (*) (void *)) (freefun), \
+ (h)->user_data)
+
+ #define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun,
freefun, arg) \
+ _obstack_begin_1 ((h), (size), (alignment), \
+ (void *(*) (void *, long)) (chunkfun), \
+ (void (*) (void *, void *)) (freefun), \
+ (arg), (h)->user_data)
+
+ #else /* OBSTACK_THREAD_SAFE */
+
#define obstack_init(h) \
_obstack_begin ((h), 0, 0, \
(void *(*) (long)) obstack_chunk_alloc, \
***************
*** 241,246 ****
--- 296,303 ----
_obstack_begin_1 ((h), (size), (alignment), \
(void *(*) (void *, long)) (chunkfun), \
(void (*) (void *, void *)) (freefun), (arg))
+
+ #endif /* OBSTACK_THREAD_SAFE */
#define obstack_chunkfun(h, newchunkfun) \
((h) -> chunkfun = (struct _obstack_chunk *(*)(void *, long))
(newchunkfun))
*** obstack.c.~1.35.~ Mon Jul 23 09:59:03 2007
--- obstack.c Sun Aug 26 14:36:47 2007
***************
*** 90,97 ****
--- 90,102 ----
abort gracefully or use longjump - but shouldn't return. This
variable by default points to the internal function
`print_and_abort'. */
+ #ifdef OBSTACK_THREAD_SAFE
+ static void print_and_abort (void *);
+ void (*obstack_alloc_failed_handler) (void *) = print_and_abort;
+ #else
static void print_and_abort (void);
void (*obstack_alloc_failed_handler) (void) = print_and_abort;
+ #endif /* OBSTACK_THREAD_SAFE */
/* Exit value used when `print_and_abort' is used. */
# include <stdlib.h>
*************** compat_symbol (libc, _obstack_compat, _o
*** 144,150 ****
_obstack_begin (struct obstack *h,
int size, int alignment,
void *(*chunkfun) (long),
! void (*freefun) (void *))
{
register struct _obstack_chunk *chunk; /* points to new chunk */
--- 149,159 ----
_obstack_begin (struct obstack *h,
int size, int alignment,
void *(*chunkfun) (long),
! void (*freefun) (void *)
! #ifdef OBSTACK_THREAD_SAFE
! , void *user_data
! #endif
! )
{
register struct _obstack_chunk *chunk; /* points to new chunk */
*************** _obstack_begin (struct obstack *h,
*** 172,181 ****
--- 181,197 ----
h->chunk_size = size;
h->alignment_mask = alignment - 1;
h->use_extra_arg = 0;
+ #ifdef OBSTACK_THREAD_SAFE
+ set_obstack_user_data (h, user_data);
+ #endif
chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
if (!chunk)
+ #ifdef OBSTACK_THREAD_SAFE
+ (*obstack_alloc_failed_handler) (obstack_user_data (h));
+ #else
(*obstack_alloc_failed_handler) ();
+ #endif
h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk,
chunk->contents,
alignment - 1);
h->chunk_limit = chunk->limit
*************** _obstack_begin (struct obstack *h,
*** 191,197 ****
_obstack_begin_1 (struct obstack *h, int size, int alignment,
void *(*chunkfun) (void *, long),
void (*freefun) (void *, void *),
! void *arg)
{
register struct _obstack_chunk *chunk; /* points to new chunk */
--- 207,217 ----
_obstack_begin_1 (struct obstack *h, int size, int alignment,
void *(*chunkfun) (void *, long),
void (*freefun) (void *, void *),
! void *arg
! #ifdef OBSTACK_THREAD_SAFE
! , void *user_data
! #endif
! )
{
register struct _obstack_chunk *chunk; /* points to new chunk */
*************** _obstack_begin_1 (struct obstack *h, int
*** 220,229 ****
--- 240,256 ----
h->alignment_mask = alignment - 1;
h->extra_arg = arg;
h->use_extra_arg = 1;
+ #ifdef OBSTACK_THREAD_SAFE
+ set_obstack_user_data (h, user_data);
+ #endif
chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
if (!chunk)
+ #ifdef OBSTACK_THREAD_SAFE
+ (*obstack_alloc_failed_handler) (obstack_user_data (h));
+ #else
(*obstack_alloc_failed_handler) ();
+ #endif
h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk,
chunk->contents,
alignment - 1);
h->chunk_limit = chunk->limit
*************** _obstack_newchunk (struct obstack *h, in
*** 260,266 ****
--- 287,297 ----
/* Allocate and initialize the new chunk. */
new_chunk = CALL_CHUNKFUN (h, new_size);
if (!new_chunk)
+ #ifdef OBSTACK_THREAD_SAFE
+ (*obstack_alloc_failed_handler) (obstack_user_data (h));
+ #else
(*obstack_alloc_failed_handler) ();
+ #endif
h->chunk = new_chunk;
new_chunk->prev = old_chunk;
new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
*************** _obstack_memory_used (struct obstack *h)
*** 413,419 ****
static void
__attribute__ ((noreturn))
! print_and_abort (void)
{
/* Don't change any of these strings. Yes, it would be possible to add
the newline to the string and use fputs or so. But this must not
--- 444,456 ----
static void
__attribute__ ((noreturn))
! print_and_abort (
! #ifdef OBSTACK_THREAD_SAFE
! void *user_data
! #else
! void
! #endif
! )
{
/* Don't change any of these strings. Yes, it would be possible to add
the newline to the string and use fputs or so. But this must not
_________________________________________________________________
Express yourself instantly with MSN Messenger! Download today it's FREE!
http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/