(this is for review by people who know better than me :)
[ some functions are replaced here by lower case versions because this code is not part of dlls/ntdll/thread.c. consequently, we have to dlopen() that library, and dlsym() the functions we need. if this ever makes it into Wine, this will go away ]
/*********************************************************************** * adopt_thread - take an existing linux thread (of some kind) and make win32 aware of it */ int WineAdoptThread (void) { TEB *teb; void *addr; ULONG size; struct wine_pthread_thread_info thread_info; struct debug_info debug_info; int request_fd; int tid;
debug_info.str_pos = debug_info.strings; debug_info.out_pos = debug_info.output;
teb = shared_alloc_teb( &size ); teb->tibflags = TEBF_WIN32; teb->exit_code = STILL_ACTIVE; teb->request_fd = -1; teb->reply_fd = -1; teb->wait_fd[0] = -1; teb->wait_fd[1] = -1; teb->debug_info = &debug_info; teb->htask16 = NtCurrentTeb()->htask16;
thread_info.stack_base = NULL; thread_info.stack_size = 0; thread_info.teb_base = teb; thread_info.teb_size = size; thread_info.teb_sel = teb->teb_sel;
wine_pthread_init_current_teb( &thread_info );
SERVER_START_REQ( new_thread ) { size_t rsz = sizeof (*req);
req->suspend = FALSE; req->inherit = 0; /* FIXME */
pthread_mutex_lock (&proxy_thread_lock);
if (write (proxy_pipe_request[1], &__req, sizeof (__req)) != sizeof (__req) || read (proxy_pipe_status[0], &__req, sizeof (__req)) != sizeof (__req) || read (proxy_pipe_status[0], &request_fd, sizeof (request_fd)) != sizeof (request_fd)) { fst_error ("cannot read/write proxy thread request (%s)", strerror (errno)); }
pthread_mutex_unlock (&proxy_thread_lock); if (request_fd >= 0) { tid = reply->tid; } fst_error ("request FD for adopted thread is %d\n", request_fd);
} SERVER_END_REQ;
if (request_fd < 0) goto error;
teb->ClientId.UniqueProcess = (HANDLE)GetCurrentProcessId(); teb->ClientId.UniqueThread = (HANDLE)tid; teb->request_fd = request_fd;
/* don't bother with signal initialization since we redirect all signals back to linux anyway. */ /* SIGNAL_Init(); */
/* server_*/ init_thread( thread_info.pid, thread_info.tid, NULL ); wine_pthread_init_thread( &thread_info );
/* create a memory view for the TEB */ ntallocatevm ( GetCurrentProcess(), &addr, teb, &size, MEM_SYSTEM, PAGE_EXECUTE_READWRITE );
/* allocate a memory view for the stack */ size = thread_info.stack_size; ntallocatevm ( GetCurrentProcess(), &teb->DeallocationStack, thread_info.stack_base, &size, MEM_SYSTEM, PAGE_EXECUTE_READWRITE ); /* limit is lower than base since the stack grows down */ teb->Tib.StackBase = (char *)thread_info.stack_base + thread_info.stack_size; teb->Tib.StackLimit = thread_info.stack_base;
/* setup the guard page */ size = 1; ntprotectvm ( GetCurrentProcess(), &teb->DeallocationStack, &size, PAGE_EXECUTE_READWRITE | PAGE_GUARD, NULL );
acquirepeblock (); InsertHeadList( &tls_link_head, &teb->TlsLinks ); releasepeblock ();
fprintf (stderr, "thread adopted\n");
return 0;
error: shared_free_teb (teb); /* XXX deallocate VM */ /* close thread handle */ close (request_fd); return -1; }