(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;
}