On Monday 21 April 2003 10:55 pm, Alexandre Julliard wrote:
"Dimitrie O. Paun" dpaun@rogers.com writes:
Just like with threads, why not cross that bridge when we get there? Is it really worth it to penalize 99% of the people? When we port to another compiler, it will be a lot simpler to worry about those pieces of code, rather than have no code at all.
The difference with threads is that we know all platforms have some kind of threading, so we know that we can adapt the code when needed. I don't think any other C compiler supports local functions (even g++ doesn't AFAIK), so there won't be much hope of ever making it work. Of course we could decide to stop supporting other compilers, but I don't think everybody would be happy with that.
Also, not accepting code into Wine that depend on exception is one thing, but what about Winelib? We can have the exception code commented out if __WINESRC__ is defined, but at least lets get it in if it works, it will plug a big Winelib hole.
Sure, we can make the macros available for Winelib.
OK, folks, I think I may have a plan to create a portable __except, please let me know your thoughts, as there are many places I might be going wrong. What follows is a totally new approach compared to my old attempts; I haven't tried to implement a similar implementation "plan" for __finally yet.
Allright, here goes, in crap / gibberish ("pseudocode") form:
/* GLOBAL structure instance somewhere (ntdll?) Thread-local */ typedef struct { bool do_handler_bit; DWORD exception_code; jmp_buf jmp; } SEH_TLS_TEMP;
SEH_TLS_TEMP SEH_TLS_TEMPS;
WINE_EXCEPTION_HANDLER_FUNC WineSEHHandler(args) { if (setjmp(SEH_TLS_TEMPS.jmp)) { switch(SEH_TLS_TEMPS.exception_code) ... /* the rest is like __wine_exception_handler in ntdll/exception.c */ } else { do_handler_bit = 0; longjmp(exception_record_argument->jmpbuf, 0); } }
/* now here are the parts that would be in include/wine/exception.h */
/* exactly the same as __TRY, really just #define __try __TRY */ #define __try \ do { __WINE_FRAME __f; \ int __first = 1; \ for (;;) if (!__first) \ { \ do {
#define __except(expr) \ } while(0); \ SEH_TLS_TEMPS.do_handler_bit = 0; __wine_pop_frame( &__f.frame ); \ break; \ } else { \ __f.frame.Handler = (PEXCEPTION_HANDLER) WineSEHHandler; \ __f.u.filter = NULL; \ __wine_push_frame( &__f.frame ); \ if (setjmp( __f.jmp)) { \ int ecode; \ const __WINE_FRAME * const __eptr WINE_UNUSED = &__f; \ /* exception code hacks go here... */ \ if ((ecode = (expr)) != EXECUTE_HANDLER) { \ SEH_TLS_TEMPS.exception_code = ecode \ longjmp(SEH_TLS_TEMPS.jmp, 0); \ } \ RtlUnwind(...); \ __wine_pop_frame(); SEH_TLS_TEMPS.do_handler_bit = 1; \ break; \ } \ __first = 0; \ } \ } while (0); \ if (SEH_TLS_TEMPS.do_handler_bit)
This obviously is leaving some stuff out. For example, this wouldn't work with nested exceptions. However, that seems possible to fix, if not by abusing the jmp_buf right in the frame structure then by creating a stack of SEH_TLS_TEMP structures instead of just a single instance, or maybe in some other clever way like attaching the SEH_TLS_TEMP struct to the wine frame struct.
What I'm more concerned about is the following:
A() runs setjmp, calls B(), which calls C(), which calls D(). A() would be the user's function (whatever it is) and D() would be WineSEHHandler above. D() runs setjmp again on a second jump buffer, and calls longjmp to do a nonlocal goto into A().
Now:
(a) if the exception code runs, A() keeps running and eventually just returns... will it properly release all the stack from B(), C() and so on or is this a problem? I guess its OK since the SP just goes back to what it was when I called setjmp, right?
(b) if the exception code doesn't run, A() runs longjmp again, to non-local goto /back/ into D(), using the second jmp_buf. This returns normally and would, I guess, expect to unwind the stack normally through C(), B() and so on... (this is all ignoring the fact that flow-of-control was interrupted by an exception, but for my purposes I don't think it matters).
Are either of these scenarios illegal (in wine)? If not, I think I can make it work. Another concern would be that two longjmps are just too slow to be used, but since that only occurs in an exception scenario I think it's OK...
Thoughts, flames, etc?