diff --git a/dlls/kernel/tests/thread.c b/dlls/kernel/tests/thread.c index ed1224dc331..a6a4f7b935e 100644 --- a/dlls/kernel/tests/thread.c +++ b/dlls/kernel/tests/thread.c @@ -607,6 +607,44 @@ static VOID test_GetThreadExitCode(void) ok(CloseHandle(thread)!=0,"Error closing thread handle\n"); } +#ifdef __i386__ + +static int test_value = 0; + +static void set_test_val( int val ) +{ + test_value += val; +} + +static DWORD WINAPI threadFunc6(LPVOID p) +{ + test_value *= (int)p; + return 0; +} + +static void test_SetThreadContext(void) +{ + CONTEXT ctx; + int *stack; + HANDLE thread = CreateThread( NULL, 0, threadFunc6, (void *)2, CREATE_SUSPENDED, NULL ); + + ctx.ContextFlags = CONTEXT_FULL; + ok( GetThreadContext( thread, &ctx ), "GetThreadContext failed\n" ); + /* simulate a call to set_test_val(10) */ + stack = (int *)ctx.Esp; + stack[-1] = 10; + stack[-2] = ctx.Eip; + ctx.Esp -= 2 * sizeof(int *); + ctx.Eip = (DWORD)set_test_val; + ok( SetThreadContext( thread, &ctx ), "SetThreadContext failed\n" ); + ResumeThread( thread ); + WaitForSingleObject( thread, INFINITE ); + ok( test_value == 20, "test_value %d instead of 20\n", test_value ); +} + +#endif /* __i386__ */ + + START_TEST(thread) { HINSTANCE lib; @@ -628,4 +666,7 @@ START_TEST(thread) test_GetThreadTimes(); test_thread_processor(); test_GetThreadExitCode(); +#ifdef __i386__ + test_SetThreadContext(); +#endif } diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index 8265bf3bc32..15e7ae16919 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -142,6 +142,43 @@ extern DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_R PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler); #endif +/********************************************************************** + * wait_suspend + * + * Wait until the thread is no longer suspended. + */ +void wait_suspend( CONTEXT *context ) +{ + LARGE_INTEGER timeout; + + /* store the context we got at suspend time */ + SERVER_START_REQ( set_thread_context ) + { + req->handle = GetCurrentThread(); + req->flags = CONTEXT_FULL; + req->suspend = 1; + wine_server_add_data( req, context, sizeof(*context) ); + wine_server_call( req ); + } + SERVER_END_REQ; + + /* wait with 0 timeout, will only return once the thread is no longer suspended */ + timeout.QuadPart = 0; + NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout, 0 ); + + /* retrieve the new context */ + SERVER_START_REQ( get_thread_context ) + { + req->handle = GetCurrentThread(); + req->flags = CONTEXT_FULL; + req->suspend = 1; + wine_server_set_reply( req, context, sizeof(*context) ); + wine_server_call( req ); + } + SERVER_END_REQ; +} + + /********************************************************************** * send_debug_event * diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index ea6a00dd31f..9e8809dbf9b 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -30,6 +30,8 @@ #define MAX_NT_PATH_LENGTH 277 +/* exceptions */ +extern void wait_suspend( CONTEXT *context ); extern void WINAPI __regs_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT ); /* debug helper */ diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 4b6a0ea8f53..8d4aca30668 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -85,7 +85,7 @@ typedef struct unsigned long i387; unsigned long oldmask; unsigned long cr2; -} SIGCONTEXT; +} volatile SIGCONTEXT; #define HANDLER_DEF(name) void name( int __signal, SIGCONTEXT __context ) #define HANDLER_CONTEXT (&__context) @@ -641,12 +641,24 @@ typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context ); * * Handler initialization when the full context is not needed. */ -static void *init_handler( const SIGCONTEXT *sigcontext ) +inline static void *init_handler( const SIGCONTEXT *sigcontext, WORD *fs, WORD *gs ) { void *stack = (void *)ESP_sig(sigcontext); TEB *teb = get_current_teb(); struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; + /* get %fs and %gs at time of the fault */ +#ifdef FS_sig + *fs = LOWORD(FS_sig(sigcontext)); +#else + *fs = wine_get_fs(); +#endif +#ifdef GS_sig + *gs = LOWORD(GS_sig(sigcontext)); +#else + *gs = wine_get_gs(); +#endif + wine_set_fs( thread_data->teb_sel ); /* now restore a proper %gs for the fault handler */ @@ -717,6 +729,67 @@ inline static void restore_fpu( CONTEXT *context ) } +/*********************************************************************** + * save_context + * + * Build a context structure from the signal info. + */ +inline static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext, WORD fs, WORD gs ) +{ + context->ContextFlags = CONTEXT_FULL; + context->Eax = EAX_sig(sigcontext); + context->Ebx = EBX_sig(sigcontext); + context->Ecx = ECX_sig(sigcontext); + context->Edx = EDX_sig(sigcontext); + context->Esi = ESI_sig(sigcontext); + context->Edi = EDI_sig(sigcontext); + context->Ebp = EBP_sig(sigcontext); + context->EFlags = EFL_sig(sigcontext); + context->Eip = EIP_sig(sigcontext); + context->Esp = ESP_sig(sigcontext); + context->SegCs = LOWORD(CS_sig(sigcontext)); + context->SegDs = LOWORD(DS_sig(sigcontext)); + context->SegEs = LOWORD(ES_sig(sigcontext)); + context->SegFs = fs; + context->SegGs = gs; + context->SegSs = LOWORD(SS_sig(sigcontext)); +} + + +/*********************************************************************** + * restore_context + * + * Restore the signal info from the context. + */ +inline static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext ) +{ + EAX_sig(sigcontext) = context->Eax; + EBX_sig(sigcontext) = context->Ebx; + ECX_sig(sigcontext) = context->Ecx; + EDX_sig(sigcontext) = context->Edx; + ESI_sig(sigcontext) = context->Esi; + EDI_sig(sigcontext) = context->Edi; + EBP_sig(sigcontext) = context->Ebp; + EFL_sig(sigcontext) = context->EFlags; + EIP_sig(sigcontext) = context->Eip; + ESP_sig(sigcontext) = context->Esp; + CS_sig(sigcontext) = context->SegCs; + DS_sig(sigcontext) = context->SegDs; + ES_sig(sigcontext) = context->SegEs; + SS_sig(sigcontext) = context->SegSs; +#ifdef GS_sig + GS_sig(sigcontext) = context->SegGs; +#else + wine_set_gs( context->SegGs ); +#endif +#ifdef FS_sig + FS_sig(sigcontext) = context->SegFs; +#else + wine_set_fs( context->SegFs ); +#endif +} + + /*********************************************************************** * setup_exception * @@ -740,19 +813,7 @@ static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func fun WORD fs, gs; - /* get %fs and %gs at time of the fault */ -#ifdef FS_sig - fs = LOWORD(FS_sig(sigcontext)); -#else - fs = wine_get_fs(); -#endif -#ifdef GS_sig - gs = LOWORD(GS_sig(sigcontext)); -#else - gs = wine_get_gs(); -#endif - - stack = init_handler( sigcontext ); + stack = init_handler( sigcontext, &fs, &gs ); /* stack sanity checks */ @@ -792,23 +853,7 @@ static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func fun stack->rec.ExceptionAddress = (LPVOID)EIP_sig(sigcontext); stack->rec.NumberParameters = 0; - stack->context.ContextFlags = CONTEXT_FULL; - stack->context.Eax = EAX_sig(sigcontext); - stack->context.Ebx = EBX_sig(sigcontext); - stack->context.Ecx = ECX_sig(sigcontext); - stack->context.Edx = EDX_sig(sigcontext); - stack->context.Esi = ESI_sig(sigcontext); - stack->context.Edi = EDI_sig(sigcontext); - stack->context.Ebp = EBP_sig(sigcontext); - stack->context.EFlags = EFL_sig(sigcontext); - stack->context.Eip = EIP_sig(sigcontext); - stack->context.Esp = ESP_sig(sigcontext); - stack->context.SegCs = LOWORD(CS_sig(sigcontext)); - stack->context.SegDs = LOWORD(DS_sig(sigcontext)); - stack->context.SegEs = LOWORD(ES_sig(sigcontext)); - stack->context.SegFs = fs; - stack->context.SegGs = gs; - stack->context.SegSs = LOWORD(SS_sig(sigcontext)); + save_context( &stack->context, sigcontext, fs, gs ); /* now modify the sigcontext to return to the raise function */ ESP_sig(sigcontext) = (DWORD)stack; @@ -1108,10 +1153,13 @@ static HANDLER_DEF(fpe_handler) * int_handler * * Handler for SIGINT. + * + * FIXME: should not be calling external functions on the signal stack. */ static HANDLER_DEF(int_handler) { - init_handler( HANDLER_CONTEXT ); + WORD fs, gs; + init_handler( HANDLER_CONTEXT, &fs, &gs ); if (!dispatch_signal(SIGINT)) { EXCEPTION_RECORD *rec = setup_exception( HANDLER_CONTEXT, __regs_RtlRaiseException ); @@ -1139,7 +1187,8 @@ static HANDLER_DEF(abrt_handler) */ static HANDLER_DEF(term_handler) { - init_handler( HANDLER_CONTEXT ); + WORD fs, gs; + init_handler( HANDLER_CONTEXT, &fs, &gs ); server_abort_thread(0); } @@ -1151,12 +1200,13 @@ static HANDLER_DEF(term_handler) */ static HANDLER_DEF(usr1_handler) { - LARGE_INTEGER timeout; + WORD fs, gs; + CONTEXT context; - init_handler( HANDLER_CONTEXT ); - /* wait with 0 timeout, will only return once the thread is no longer suspended */ - timeout.QuadPart = 0; - NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout, 0 ); + init_handler( HANDLER_CONTEXT, &fs, &gs ); + save_context( &context, HANDLER_CONTEXT, fs, gs ); + wait_suspend( &context ); + restore_context( &context, HANDLER_CONTEXT ); } @@ -1198,6 +1248,7 @@ static int set_handler( int sig, int have_sigaltstack, void (*func)() ) sig_act.ksa_handler = func; sig_act.ksa_flags = SA_RESTART; sig_act.ksa_mask = (1 << (SIGINT-1)) | + (1 << (SIGUSR1-1)) | (1 << (SIGUSR2-1)); /* point to the top of the signal stack */ sig_act.ksa_restorer = (char *)get_signal_stack() + signal_stack_size; @@ -1207,6 +1258,7 @@ static int set_handler( int sig, int have_sigaltstack, void (*func)() ) sig_act.sa_handler = func; sigemptyset( &sig_act.sa_mask ); sigaddset( &sig_act.sa_mask, SIGINT ); + sigaddset( &sig_act.sa_mask, SIGUSR1 ); sigaddset( &sig_act.sa_mask, SIGUSR2 ); #if defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) diff --git a/dlls/ntdll/signal_powerpc.c b/dlls/ntdll/signal_powerpc.c index 3c976f56b29..d60075ccb02 100644 --- a/dlls/ntdll/signal_powerpc.c +++ b/dlls/ntdll/signal_powerpc.c @@ -577,11 +577,11 @@ static HANDLER_DEF(term_handler) */ static HANDLER_DEF(usr1_handler) { - LARGE_INTEGER timeout; + CONTEXT context; - /* wait with 0 timeout, will only return once the thread is no longer suspended */ - timeout.QuadPart = 0; - NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout, 0 ); + save_context( &context, HANDLER_CONTEXT ); + wait_suspend( &context ); + restore_context( &context, HANDLER_CONTEXT ); } diff --git a/dlls/ntdll/signal_sparc.c b/dlls/ntdll/signal_sparc.c index 85786b3ee5e..ef5e760c29d 100644 --- a/dlls/ntdll/signal_sparc.c +++ b/dlls/ntdll/signal_sparc.c @@ -384,11 +384,11 @@ static HANDLER_DEF(term_handler) */ static HANDLER_DEF(usr1_handler) { - LARGE_INTEGER timeout; + CONTEXT context; - /* wait with 0 timeout, will only return once the thread is no longer suspended */ - timeout.QuadPart = 0; - NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout, 0 ); + save_context( &context, HANDLER_CONTEXT ); + wait_suspend( &context ); + restore_context( &context, HANDLER_CONTEXT ); } diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 5a83a530b6f..271e0a981dd 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -408,11 +408,11 @@ static HANDLER_DEF(term_handler) */ static HANDLER_DEF(usr1_handler) { - LARGE_INTEGER timeout; + CONTEXT context; - /* wait with 0 timeout, will only return once the thread is no longer suspended */ - timeout.QuadPart = 0; - NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout, 0 ); + save_context( &context, HANDLER_CONTEXT ); + wait_suspend( &context ); + restore_context( &context, HANDLER_CONTEXT ); } diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 2b291d5331b..d9faa7e8254 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -485,15 +485,41 @@ NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1 NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context ) { NTSTATUS ret; + DWORD dummy, i; SERVER_START_REQ( set_thread_context ) { - req->handle = handle; - req->flags = context->ContextFlags; + req->handle = handle; + req->flags = context->ContextFlags; + req->suspend = 0; wine_server_add_data( req, context, sizeof(*context) ); ret = wine_server_call( req ); } SERVER_END_REQ; + + if (ret == STATUS_PENDING) + { + if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS) + { + for (i = 0; i < 100; i++) + { + SERVER_START_REQ( set_thread_context ) + { + req->handle = handle; + req->flags = context->ContextFlags; + req->suspend = 0; + wine_server_add_data( req, context, sizeof(*context) ); + ret = wine_server_call( req ); + } + SERVER_END_REQ; + if (ret != STATUS_PENDING) break; + NtYieldExecution(); + } + NtResumeThread( handle, &dummy ); + } + } + + if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED; return ret; } @@ -731,16 +757,42 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) { NTSTATUS ret; CONTEXT ctx; + DWORD dummy, i; SERVER_START_REQ( get_thread_context ) { - req->handle = handle; - req->flags = context->ContextFlags; + req->handle = handle; + req->flags = context->ContextFlags; + req->suspend = 0; wine_server_set_reply( req, &ctx, sizeof(ctx) ); ret = wine_server_call( req ); } SERVER_END_REQ; + + if (ret == STATUS_PENDING) + { + if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS) + { + for (i = 0; i < 100; i++) + { + SERVER_START_REQ( get_thread_context ) + { + req->handle = handle; + req->flags = context->ContextFlags; + req->suspend = 0; + wine_server_set_reply( req, &ctx, sizeof(ctx) ); + ret = wine_server_call( req ); + } + SERVER_END_REQ; + if (ret != STATUS_PENDING) break; + NtYieldExecution(); + } + NtResumeThread( handle, &dummy ); + } + } + if (ret == STATUS_SUCCESS) copy_context( context, &ctx, context->ContextFlags ); + else if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED; return ret; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index b4a34c91090..4a241510ca6 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1572,7 +1572,6 @@ struct get_exception_status_request struct get_exception_status_reply { struct reply_header __header; - int status; /* VARARG(context,context); */ }; @@ -1952,6 +1951,7 @@ struct get_thread_context_request struct request_header __header; obj_handle_t handle; unsigned int flags; + int suspend; }; struct get_thread_context_reply { @@ -1966,6 +1966,7 @@ struct set_thread_context_request struct request_header __header; obj_handle_t handle; unsigned int flags; + int suspend; /* VARARG(context,context); */ }; struct set_thread_context_reply @@ -4207,6 +4208,6 @@ union generic_reply struct set_mailslot_info_reply set_mailslot_info_reply; }; -#define SERVER_PROTOCOL_VERSION 196 +#define SERVER_PROTOCOL_VERSION 197 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 135e2bbeff3..b5bfd5dc13c 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1401,6 +1401,7 @@ enum char_info_mode @REQ(get_thread_context) obj_handle_t handle; /* thread handle */ unsigned int flags; /* context flags */ + int suspend; /* if getting context during suspend */ @REPLY VARARG(context,context); /* thread context */ @END @@ -1410,6 +1411,7 @@ enum char_info_mode @REQ(set_thread_context) obj_handle_t handle; /* thread handle */ unsigned int flags; /* context flags */ + int suspend; /* if setting context during suspend */ VARARG(context,context); /* thread context */ @END diff --git a/server/thread.c b/server/thread.c index c8b8d79e096..3339e9dfb9a 100644 --- a/server/thread.c +++ b/server/thread.c @@ -118,6 +118,7 @@ inline static void init_thread_structure( struct thread *thread ) thread->unix_pid = -1; /* not known yet */ thread->unix_tid = -1; /* not known yet */ thread->context = NULL; + thread->suspend_context = NULL; thread->teb = NULL; thread->debug_ctx = NULL; thread->debug_event = NULL; @@ -212,6 +213,7 @@ static void cleanup_thread( struct thread *thread ) if (thread->request_fd) release_object( thread->request_fd ); if (thread->reply_fd) release_object( thread->reply_fd ); if (thread->wait_fd) release_object( thread->wait_fd ); + if (thread->suspend_context) free( thread->suspend_context ); free_msg_queue( thread ); cleanup_clipboard_thread(thread); destroy_thread_windows( thread ); @@ -229,19 +231,19 @@ static void cleanup_thread( struct thread *thread ) thread->request_fd = NULL; thread->reply_fd = NULL; thread->wait_fd = NULL; + thread->context = NULL; + thread->suspend_context = NULL; thread->desktop = 0; } /* destroy a thread when its refcount is 0 */ static void destroy_thread( struct object *obj ) { - struct thread_apc *apc; struct thread *thread = (struct thread *)obj; assert( obj->ops == &thread_ops ); assert( !thread->debug_ctx ); /* cannot still be debugging something */ list_remove( &thread->entry ); - while ((apc = thread_dequeue_apc( thread, 0 ))) free( apc ); cleanup_thread( thread ); release_object( thread->process ); if (thread->id) free_ptid( thread->id ); @@ -1053,7 +1055,27 @@ DECL_HANDLER(get_thread_context) } if (!(thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT ))) return; - if ((data = set_reply_data_size( sizeof(CONTEXT) ))) + if (req->suspend) + { + if (thread != current || !thread->suspend_context) + { + /* not suspended, shouldn't happen */ + set_error( STATUS_INVALID_PARAMETER ); + } + else + { + if (thread->context == thread->suspend_context) thread->context = NULL; + set_reply_data_ptr( thread->suspend_context, sizeof(CONTEXT) ); + thread->suspend_context = NULL; + } + } + else if (thread != current && !thread->context) + { + /* thread is not suspended, retry (if it's still running) */ + if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED ); + else set_error( STATUS_PENDING ); + } + else if ((data = set_reply_data_size( sizeof(CONTEXT) ))) { memset( data, 0, sizeof(CONTEXT) ); get_thread_context( thread, data, req->flags ); @@ -1071,11 +1093,32 @@ DECL_HANDLER(set_thread_context) set_error( STATUS_INVALID_PARAMETER ); return; } - if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT ))) + if (!(thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT ))) return; + + if (req->suspend) + { + if (thread != current || thread->context) + { + /* nested suspend or exception, shouldn't happen */ + set_error( STATUS_INVALID_PARAMETER ); + } + else if ((thread->suspend_context = mem_alloc( sizeof(CONTEXT) ))) + { + memcpy( thread->suspend_context, get_req_data(), sizeof(CONTEXT) ); + thread->context = thread->suspend_context; + } + } + else if (thread != current && !thread->context) + { + /* thread is not suspended, retry (if it's still running) */ + if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED ); + else set_error( STATUS_PENDING ); + } + else { set_thread_context( thread, get_req_data(), req->flags ); - release_object( thread ); } + release_object( thread ); } /* fetch a selector entry for a thread */ diff --git a/server/thread.h b/server/thread.h index 47bc791c09b..64ebfe9c40a 100644 --- a/server/thread.h +++ b/server/thread.h @@ -78,6 +78,7 @@ struct thread int unix_pid; /* Unix pid of client */ int unix_tid; /* Unix tid of client */ CONTEXT *context; /* current context if in an exception handler */ + CONTEXT *suspend_context; /* current context if suspended */ void *teb; /* TEB address (in client address space) */ int priority; /* priority level */ int affinity; /* affinity mask */ diff --git a/server/trace.c b/server/trace.c index b614e7a2e1c..622f0c76311 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1577,7 +1577,6 @@ static void dump_get_exception_status_request( const struct get_exception_status static void dump_get_exception_status_reply( const struct get_exception_status_reply *req ) { - fprintf( stderr, " status=%d,", req->status ); fprintf( stderr, " context=" ); dump_varargs_context( cur_size ); } @@ -1856,7 +1855,8 @@ static void dump_get_timer_info_reply( const struct get_timer_info_reply *req ) static void dump_get_thread_context_request( const struct get_thread_context_request *req ) { fprintf( stderr, " handle=%p,", req->handle ); - fprintf( stderr, " flags=%08x", req->flags ); + fprintf( stderr, " flags=%08x,", req->flags ); + fprintf( stderr, " suspend=%d", req->suspend ); } static void dump_get_thread_context_reply( const struct get_thread_context_reply *req ) @@ -1869,6 +1869,7 @@ static void dump_set_thread_context_request( const struct set_thread_context_req { fprintf( stderr, " handle=%p,", req->handle ); fprintf( stderr, " flags=%08x,", req->flags ); + fprintf( stderr, " suspend=%d,", req->suspend ); fprintf( stderr, " context=" ); dump_varargs_context( cur_size ); } @@ -3740,6 +3741,7 @@ static const struct { "FILE_IS_A_DIRECTORY", STATUS_FILE_IS_A_DIRECTORY }, { "FILE_LOCK_CONFLICT", STATUS_FILE_LOCK_CONFLICT }, { "HANDLE_NOT_CLOSABLE", STATUS_HANDLE_NOT_CLOSABLE }, + { "INSTANCE_NOT_AVAILABLE", STATUS_INSTANCE_NOT_AVAILABLE }, { "INVALID_CID", STATUS_INVALID_CID }, { "INVALID_FILE_FOR_SECTION", STATUS_INVALID_FILE_FOR_SECTION }, { "INVALID_HANDLE", STATUS_INVALID_HANDLE },