From 5457dfcb8174f0ff25a0522050c1d79e710a68df Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Tue, 17 Jul 2001 03:41:52 +0000 Subject: [PATCH] * child_info.h: Bump magic number. (class child_info): Add an element. * cygheap.cc (init_cheap): Allocate cygwin heap in shared memory area. (cygheap_fixup_in_child): Map cygwin heap, passed from parent via shared memory into correct address. (cygheap_setup_for_child): New function. * cygheap.h: Declare new functions. * dcrt0.cc (dll_crt0_1): Accomodate new cygheap_fixup_in_child arguments. Avoid protecting subproc_ready unless it is spawn/nowait. * fork.cc (fork_parent): Use new cygheap_setup_for_child function to setup cygwin heap info. Close passed cygheap shared memory handle. * spawn.cc (spawn_guts): Ditto. Also, reorganize to avoid synchronization between parent and child in non-P_OVERLAY case. * sigproc.cc (wait_sig): Only signal subproc_ready when execing. --- winsup/cygwin/ChangeLog | 17 +++++ winsup/cygwin/child_info.h | 3 +- winsup/cygwin/cygheap.cc | 141 ++++++++++++++++++++++--------------- winsup/cygwin/cygheap.h | 4 +- winsup/cygwin/dcrt0.cc | 9 ++- winsup/cygwin/fork.cc | 4 +- winsup/cygwin/shared.cc | 2 +- winsup/cygwin/sigproc.cc | 3 +- winsup/cygwin/spawn.cc | 129 ++++++++++++++++----------------- 9 files changed, 180 insertions(+), 132 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 6cc15f51d..68b3a5430 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,20 @@ +Mon 16 Jul 2001 10:47:17 PM EDT Christopher Faylor + + * child_info.h: Bump magic number. + (class child_info): Add an element. + * cygheap.cc (init_cheap): Allocate cygwin heap in shared memory area. + (cygheap_fixup_in_child): Map cygwin heap, passed from parent via + shared memory into correct address. + (cygheap_setup_for_child): New function. + * cygheap.h: Declare new functions. + * dcrt0.cc (dll_crt0_1): Accomodate new cygheap_fixup_in_child + arguments. Avoid protecting subproc_ready unless it is spawn/nowait. + * fork.cc (fork_parent): Use new cygheap_setup_for_child function to + setup cygwin heap info. Close passed cygheap shared memory handle. + * spawn.cc (spawn_guts): Ditto. Also, reorganize to avoid + synchronization between parent and child in non-P_OVERLAY case. + * sigproc.cc (wait_sig): Only signal subproc_ready when execing. + Mon 16 Jul 2001 15:21:00 Corinna Vinschen * grp.cc: Add missing Copyright date 2001. diff --git a/winsup/cygwin/child_info.h b/winsup/cygwin/child_info.h index 5c9904e61..c838ceda6 100644 --- a/winsup/cygwin/child_info.h +++ b/winsup/cygwin/child_info.h @@ -12,7 +12,7 @@ details. */ enum { - PROC_MAGIC = 0xaf0ff000, + PROC_MAGIC = 0xaf10f000, PROC_FORK = PROC_MAGIC + 1, PROC_EXEC = PROC_MAGIC + 2, PROC_SPAWN = PROC_MAGIC + 3, @@ -39,6 +39,7 @@ public: HANDLE pppid_handle; init_cygheap *cygheap; void *cygheap_max; + HANDLE cygheap_h; }; class child_info_fork: public child_info diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc index e22a91060..37350b1dd 100644 --- a/winsup/cygwin/cygheap.cc +++ b/winsup/cygwin/cygheap.cc @@ -17,6 +17,7 @@ #include "fhandler.h" #include "dtable.h" #include "cygheap.h" +#include "child_info.h" #include "heap.h" #include "cygerrno.h" #include "sync.h" @@ -28,15 +29,98 @@ void NO_COPY *cygheap_max = NULL; static NO_COPY muto *cygheap_protect = NULL; +struct cygheap_entry + { + int type; + struct cygheap_entry *next; + char data[0]; + }; + +#define NBUCKETS 32 +char *buckets[NBUCKETS] = {0}; + +#define N0 ((_cmalloc_entry *) NULL) +#define to_cmalloc(s) ((_cmalloc_entry *) (((char *) (s)) - (int) (N0->data))) + +extern "C" { +static void __stdcall _cfree (void *ptr) __attribute__((regparm(1))); +} + inline static void init_cheap () { - cygheap = (init_cygheap *) VirtualAlloc (NULL, CYGHEAPSIZE, MEM_RESERVE, PAGE_NOACCESS); + HANDLE cygheap_h; + cygheap_h = CreateFileMapping (INVALID_HANDLE_VALUE, &sec_none_nih, + PAGE_READWRITE | SEC_RESERVE, 0, CYGHEAPSIZE, + NULL); + cygheap = (init_cygheap *) MapViewOfFileEx (cygheap_h, + FILE_MAP_READ | FILE_MAP_WRITE, + 0, 0, 0, NULL); + CloseHandle (cygheap_h); if (!cygheap) api_fatal ("Couldn't reserve space for cygwin's heap, %E"); cygheap_max = cygheap + 1; } +void __stdcall +cygheap_setup_for_child (child_info *ci) +{ + void *newcygheap; + cygheap_protect->acquire (); + unsigned n = (char *) cygheap_max - (char *) cygheap; + ci->cygheap_h = CreateFileMapping (INVALID_HANDLE_VALUE, &sec_none, + PAGE_READWRITE | SEC_RESERVE, 0, + CYGHEAPSIZE, NULL); + newcygheap = MapViewOfFileEx (ci->cygheap_h, FILE_MAP_READ | FILE_MAP_WRITE, + 0, 0, 0, NULL); + if (!VirtualAlloc (newcygheap, n, MEM_COMMIT, PAGE_READWRITE)) + api_fatal ("couldn't allocate new heap for child, %E"); + memcpy (newcygheap, cygheap, n); + UnmapViewOfFile (newcygheap); + ci->cygheap = cygheap; + ci->cygheap_max = cygheap_max; + ProtectHandle1 (ci->cygheap_h, passed_cygheap_h); + cygheap_protect->release (); + return; +} + +/* Called by fork or spawn to reallocate cygwin heap */ +void __stdcall +cygheap_fixup_in_child (child_info *ci, bool execed) +{ + cygheap = ci->cygheap; + cygheap_max = ci->cygheap_max; +#if 0 + if (!DuplicateHandle (hMainProc, ci->cygheap_h, + hMainProc, &cygheap_h, 0, 0, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) + cygheap_h = ci->cygheap_h; +#endif + if (MapViewOfFileEx (ci->cygheap_h, FILE_MAP_READ | FILE_MAP_WRITE, + 0, 0, 0, cygheap) != cygheap) + api_fatal ("Couldn't allocate space for child's heap from %p, to %p, %E", + cygheap, cygheap_max); + + ForceCloseHandle1 (ci->cygheap_h, passed_cygheap_h); + cygheap_init (); + + if (execed) + { + /* Walk the allocated memory chain looking for orphaned memory from + previous execs */ + for (_cmalloc_entry *rvc = cygheap->chain; rvc; rvc = rvc->prev) + { + cygheap_entry *ce = (cygheap_entry *) rvc->data; + if (rvc->b >= NBUCKETS || ce->type <= HEAP_1_START) + continue; + else if (ce->type < HEAP_1_MAX) + ce->type += HEAP_1_MAX; /* Mark for freeing after next exec */ + else + _cfree (ce); /* Marked by parent for freeing in child */ + } + } +} + #define pagetrunc(x) ((void *) (((DWORD) (x)) & ~(4096 - 1))) static void *__stdcall @@ -76,12 +160,6 @@ cygheap_init () /* Copyright (C) 1997, 2000 DJ Delorie */ -#define NBUCKETS 32 -char *buckets[NBUCKETS] = {0}; - -#define N0 ((_cmalloc_entry *) NULL) -#define to_cmalloc(s) ((_cmalloc_entry *) (((char *) (s)) - (int) (N0->data))) - static void *_cmalloc (int size) __attribute ((regparm(1))); static void *__stdcall _crealloc (void *ptr, int size) __attribute ((regparm(2))); @@ -115,7 +193,6 @@ _cmalloc (int size) return rvc->data; } -static void __stdcall _cfree (void *ptr) __attribute__((regparm(1))); static void __stdcall _cfree (void *ptr) { @@ -150,57 +227,9 @@ _crealloc (void *ptr, int size) #define sizeof_cygheap(n) ((n) + sizeof(cygheap_entry)) -struct cygheap_entry - { - int type; - struct cygheap_entry *next; - char data[0]; - }; - #define N ((cygheap_entry *) NULL) #define tocygheap(s) ((cygheap_entry *) (((char *) (s)) - (int) (N->data))) -/* Called by fork or spawn to reallocate cygwin heap */ -extern "C" void __stdcall -cygheap_fixup_in_child (HANDLE parent, bool execed) -{ - DWORD m, n; - n = (DWORD) cygheap_max - (DWORD) cygheap; - - /* Reserve cygwin heap in same spot as parent */ - if (!VirtualAlloc (cygheap, CYGHEAPSIZE, MEM_RESERVE, PAGE_NOACCESS)) - api_fatal ("Couldn't reserve space for cygwin's heap (%p) in child, cygheap, %E", cygheap); - - /* Allocate same amount of memory as parent */ - if (!VirtualAlloc (cygheap, n, MEM_COMMIT, PAGE_READWRITE)) - api_fatal ("Couldn't allocate space for child's heap %p, size %d, %E", - cygheap, n); - - /* Copy memory from the parent */ - m = 0; - if (!ReadProcessMemory (parent, cygheap, cygheap, n, &m) || m != n) - api_fatal ("Couldn't read parent's cygwin heap %d bytes != %d, %E", - n, m); - - cygheap_init (); - - if (execed) - { - /* Walk the allocated memory chain looking for orphaned memory from - previous execs */ - for (_cmalloc_entry *rvc = cygheap->chain; rvc; rvc = rvc->prev) - { - cygheap_entry *ce = (cygheap_entry *) rvc->data; - if (rvc->b >= NBUCKETS || ce->type <= HEAP_1_START) - continue; - else if (ce->type < HEAP_1_MAX) - ce->type += HEAP_1_MAX; /* Mark for freeing after next exec */ - else - _cfree (ce); /* Marked by parent for freeing in child */ - } - } -} - inline static void * creturn (cygheap_types x, cygheap_entry * c, int len) { diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index a32085d58..0f7c917a4 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -166,9 +166,11 @@ struct init_cygheap extern init_cygheap *cygheap; extern void *cygheap_max; +class child_info; +void __stdcall cygheap_setup_for_child (child_info *ci) __attribute__ ((regparm(1))); +void __stdcall cygheap_fixup_in_child (child_info *, bool); extern "C" { void __stdcall cfree (void *) __attribute__ ((regparm(1))); -void __stdcall cygheap_fixup_in_child (HANDLE, bool); void *__stdcall cmalloc (cygheap_types, DWORD) __attribute__ ((regparm(2))); void *__stdcall crealloc (void *, DWORD) __attribute__ ((regparm(2))); void *__stdcall ccalloc (cygheap_types, DWORD, DWORD) __attribute__ ((regparm(3))); diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index cc4986949..8fdae5d8e 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -669,13 +669,11 @@ dll_crt0_1 () if (child_proc_info) { - cygheap = child_proc_info->cygheap; - cygheap_max = child_proc_info->cygheap_max; switch (child_proc_info->type) { case PROC_FORK: case PROC_FORK1: - cygheap_fixup_in_child (child_proc_info->parent, 0); + cygheap_fixup_in_child (child_proc_info, 0); alloc_stack (fork_info); set_myself (mypid); user_data->heaptop = child_proc_info->heaptop; @@ -690,7 +688,7 @@ dll_crt0_1 () hexec_proc = spawn_info->hexec_proc; around: HANDLE h; - cygheap_fixup_in_child (spawn_info->parent, 1); + cygheap_fixup_in_child (spawn_info, 1); if (!spawn_info->moreinfo->myself_pinfo || !DuplicateHandle (hMainProc, spawn_info->moreinfo->myself_pinfo, hMainProc, &h, 0, 0, @@ -709,7 +707,8 @@ dll_crt0_1 () old_title = strcpy (title_buf, spawn_info->moreinfo->old_title); cfree (spawn_info->moreinfo->old_title); } - ProtectHandle (child_proc_info->subproc_ready); + if (child_proc_info->subproc_ready) + ProtectHandle (child_proc_info->subproc_ready); myself->uid = spawn_info->moreinfo->uid; if (myself->uid == USHRT_MAX) cygheap->user.set_sid (NULL); diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index ac9f855e9..5c7bad339 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -442,8 +442,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll, RevertToSelf (); ch.parent = hParent; - ch.cygheap = cygheap; - ch.cygheap_max = cygheap_max; + cygheap_setup_for_child (&ch); #ifdef DEBUGGING if (npid_max) { @@ -477,6 +476,7 @@ out: &pi); CloseHandle (hParent); + ForceCloseHandle1 (ch.cygheap_h, passed_cygheap_h); if (!rc) { diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc index be93cfed2..5419fa4d5 100644 --- a/winsup/cygwin/shared.cc +++ b/winsup/cygwin/shared.cc @@ -86,7 +86,7 @@ open_shared (const char *name, HANDLE &shared_h, DWORD size, void *addr) /* Probably win95, so try without specifying the address. */ shared = (shared_info *) MapViewOfFileEx (shared_h, FILE_MAP_READ|FILE_MAP_WRITE, - 0,0,0,0); + 0, 0, 0, 0); } if (!shared) diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index e70a51b3a..051e62eb2 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -1103,8 +1103,7 @@ wait_sig (VOID *) * windows process waiting to see if it's started a cygwin process or not. * Signalling subproc_ready indicates that we are a cygwin process. */ - if (child_proc_info && - (child_proc_info->type == PROC_EXEC || child_proc_info->type == PROC_SPAWN)) + if (child_proc_info && child_proc_info->type == PROC_EXEC) { debug_printf ("subproc_ready %p", child_proc_info->subproc_ready); if (!SetEvent (child_proc_info->subproc_ready)) diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index d461e532b..059e070a0 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -327,8 +327,14 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv, else chtype = PROC_EXEC; - HANDLE spr = CreateEvent (&sec_all, TRUE, FALSE, NULL); - ProtectHandle (spr); + HANDLE spr; + if (mode != _P_OVERLAY) + spr = NULL; + else + { + spr = CreateEvent (&sec_all, TRUE, FALSE, NULL); + ProtectHandle (spr); + } init_child_info (chtype, &ciresrv, (mode == _P_OVERLAY) ? myself->pid : 1, spr); if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &ciresrv.parent, 0, 1, @@ -572,8 +578,7 @@ skip_arg_parsing: else envblock = winenv (envp, 0); - ciresrv.cygheap = cygheap; - ciresrv.cygheap_max = cygheap_max; + cygheap_setup_for_child (&ciresrv); /* Preallocated buffer for `sec_user' call */ char sa_buf[1024]; @@ -669,6 +674,7 @@ skip_arg_parsing: MALLOC_CHECK; if (envblock) free (envblock); + ForceCloseHandle1 (ciresrv.cygheap_h, passed_cygheap_h); MALLOC_CHECK; /* Set errno now so that debugging messages from it appear before our @@ -741,88 +747,83 @@ skip_arg_parsing: DWORD res; BOOL exited; - HANDLE waitbuf[3] = {pi.hProcess, signal_arrived, spr}; - int nwait = 3; - bool saw_signal = 0; - res = 0; exited = FALSE; MALLOC_CHECK; - for (int i = 0; i < 100; i++) + if (mode == _P_OVERLAY) { - switch (WaitForMultipleObjects (nwait, waitbuf, FALSE, INFINITE)) + int nwait = 3; + HANDLE waitbuf[3] = {pi.hProcess, signal_arrived, spr}; + for (int i = 0; i < 100; i++) { - case WAIT_OBJECT_0: - sigproc_printf ("subprocess exited"); - DWORD exitcode; - if (!GetExitCodeProcess (pi.hProcess, &exitcode)) - exitcode = 1; - res |= exitcode; - exited = TRUE; - break; - case WAIT_OBJECT_0 + 1: - sigproc_printf ("signal arrived"); - reset_signal_arrived (); - saw_signal = 1; - continue; - case WAIT_OBJECT_0 + 2: - if (mode == _P_OVERLAY) + switch (WaitForMultipleObjects (nwait, waitbuf, FALSE, INFINITE)) { + case WAIT_OBJECT_0: + sigproc_printf ("subprocess exited"); + DWORD exitcode; + if (!GetExitCodeProcess (pi.hProcess, &exitcode)) + exitcode = 1; + res |= exitcode; + exited = TRUE; + break; + case WAIT_OBJECT_0 + 1: + sigproc_printf ("signal arrived"); + reset_signal_arrived (); + continue; + case WAIT_OBJECT_0 + 2: if (myself->ppid_handle) res |= EXIT_REPARENTING; if (!my_parent_is_alive ()) { - nwait = 1; + nwait = 2; sigproc_terminate (); continue; } + break; + case WAIT_FAILED: + system_printf ("wait failed: nwait %d, pid %d, winpid %d, %E", + nwait, myself->pid, myself->dwProcessId); + system_printf ("waitbuf[0] %p %d", waitbuf[0], + WaitForSingleObject (waitbuf[0], 0)); + system_printf ("waitbuf[1] %p = %d", waitbuf[1], + WaitForSingleObject (waitbuf[1], 0)); + system_printf ("waitbuf[w] %p = %d", waitbuf[2], + WaitForSingleObject (waitbuf[2], 0)); + set_errno (ECHILD); + try_to_debug (); + return -1; } break; - case WAIT_FAILED: - system_printf ("wait failed: nwait %d, pid %d, winpid %d, %E", - nwait, myself->pid, myself->dwProcessId); - system_printf ("waitbuf[0] %p %d", waitbuf[0], - WaitForSingleObject (waitbuf[0], 0)); - system_printf ("waitbuf[1] %p = %d", waitbuf[1], - WaitForSingleObject (waitbuf[1], 0)); - system_printf ("waitbuf[w] %p = %d", waitbuf[2], - WaitForSingleObject (waitbuf[2], 0)); - set_errno (ECHILD); - try_to_debug (); - return -1; } - break; - } - ForceCloseHandle (spr); + ForceCloseHandle (spr); - sigproc_printf ("res = %x", res); + sigproc_printf ("res = %x", res); - if (mode == _P_OVERLAY && (res & EXIT_REPARENTING)) - { - /* Try to reparent child process. - * Make handles to child available to parent process and exit with - * EXIT_REPARENTING status. Wait() syscall in parent will then wait - * for newly created child. - */ - HANDLE oldh = myself->hProcess; - HANDLE h = myself->ppid_handle; - sigproc_printf ("parent handle %p", h); - int rc = DuplicateHandle (hMainProc, pi.hProcess, h, &myself->hProcess, - 0, FALSE, DUPLICATE_SAME_ACCESS); - sigproc_printf ("%d = DuplicateHandle, oldh %p, newh %p", - rc, oldh, myself->hProcess); - if (!rc && my_parent_is_alive ()) + if (res & EXIT_REPARENTING) { - system_printf ("Reparent failed, parent handle %p, %E", h); - system_printf ("my dwProcessId %d, myself->dwProcessId %d", - GetCurrentProcessId (), myself->dwProcessId); - system_printf ("old hProcess %p, hProcess %p", oldh, myself->hProcess); + /* Try to reparent child process. + * Make handles to child available to parent process and exit with + * EXIT_REPARENTING status. Wait() syscall in parent will then wait + * for newly created child. + */ + HANDLE oldh = myself->hProcess; + HANDLE h = myself->ppid_handle; + sigproc_printf ("parent handle %p", h); + int rc = DuplicateHandle (hMainProc, pi.hProcess, h, &myself->hProcess, + 0, FALSE, DUPLICATE_SAME_ACCESS); + sigproc_printf ("%d = DuplicateHandle, oldh %p, newh %p", + rc, oldh, myself->hProcess); + if (!rc && my_parent_is_alive ()) + { + system_printf ("Reparent failed, parent handle %p, %E", h); + system_printf ("my dwProcessId %d, myself->dwProcessId %d", + GetCurrentProcessId (), myself->dwProcessId); + system_printf ("old hProcess %p, hProcess %p", oldh, myself->hProcess); + } } - } - if (saw_signal && mode != _P_OVERLAY) - thisframe.call_signal_handler (); + } MALLOC_CHECK;