This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
With some effort, we can make the obstack failed handling interface more sophisticated: by adding obstack-specific failed handler and user provided data, several obstacks can work together without bothering each other.
Suppose we have two obstacks in a program, which react differently to allocation failures. The first one wants to exit the program when failure happens, but the second one wants to longjmp to somewhere in order to recover from the failure. With only one global failed handler -- obstack_alloc_failed_handler, we cannot distinguish the caller in the handler in an easy way. So implementing this behavior is difficult.
However, we can solve this by adding failed handlers to obstack objects. When allocation fails, we take a look at the obstack itself. If there is a failed handler in it, we call it; otherwise, we call the global obstack_alloc_failed_handler as before.
Now suppose we have two obstacks in a program, both of them want to recover from the failure by longjmp'ing in failed handlers. Since we call failed handlers without arguments, the jumping destination cannot be decided easily, even if the handlers are obstack-specific.
So it is necessary to add user provided data to obstack object to make this easy. When allocation fails, we pass the user provided data to failed handlers, so that each handler knows where to jump in certain cases.
/* An obstack failed handler. DATA is filled in some obstack and passed to the handler. To convert DATA into a jmp_buf for example, we can decide the jumping destination easily. */
void an_obstack_failed_handler (void *data) { jmp_buf *env = (jmp_buf *) data;
longjmp (*env, 1); }
/* This function uses a jmp_buf and an obstack to support its complicated operations. It returns 0 on success and -1 on failure, but will not exit in either case. With the improved obstack interface, this function can do its job without depending any global status of the program. */
int func1 (void) { struct obstack obstack; jmp_buf func1_env; int have_errors = 0;
/* Setting up the jmp_buf. */ if (setjmp (func1_env)) { /* Put the failed handler and the jmp_buf into the obstack. */ obstack_init_sophisticatedly (&obstack, an_obstack_failed_handler, &func1_env);
/* Complicated operations... */ } else /* OK, we finish with errors. So let's set the flag and let the caller know about it. */ have_errors = 1;
obstack_free (&obstack, NULL); return have_errors ? -1 : 0; }
The above example shows an obstack inside a function. But in practice we usually put obstacks in C struct's but not functions. In such a case, the improved interface can make these objects independent to global variables, which is usually important nowadays.
The patch to this improvement is attached in this message. For compatibility issues, note that when OBSTACK_SOPHISTICATED_FAILED_HANDLING is not #define'd, the interface is exactly as before. If OBSTACK_SOPHISTICATED_FAILED_HANDLING is #define'd, except initializing and failed handling, the interface is still unchanged. At last, the behavior of obstack_init in the new interface and the old failed handling function print_and_abort is also not changed. So there is no non-compable changes.
Please review the change and consider add this patch to obstack. I would like to do any work to ensure the robustness of the improvement. Thanks.
Regards, Guanpeng Xu
Attachment:
obstack.diff
Description: Binary data
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |