summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <cgf@redhat.com>2003-09-02 02:31:07 +0000
committerChristopher Faylor <cgf@redhat.com>2003-09-02 02:31:07 +0000
commit847bc8f1111425871f5d072248868c0724ed480f (patch)
tree0f1b2e343184189e461e1805c5e20a90faaae282
parentecb6a19c62c404178226dc60151c299cdf33365f (diff)
downloadgdb-847bc8f1111425871f5d072248868c0724ed480f.tar.gz
merge from trunk
-rw-r--r--winsup/cygwin/ChangeLog151
-rw-r--r--winsup/cygwin/Makefile.in2
-rw-r--r--winsup/cygwin/autoload.cc1
-rwxr-xr-xwinsup/cygwin/configure2
-rw-r--r--winsup/cygwin/configure.in2
-rw-r--r--winsup/cygwin/cygheap.cc3
-rw-r--r--winsup/cygwin/cygheap.h2
-rwxr-xr-xwinsup/cygwin/cygserver.cc773
-rwxr-xr-xwinsup/cygwin/cygserver_client.cc528
-rwxr-xr-xwinsup/cygwin/cygserver_process.cc431
-rw-r--r--winsup/cygwin/cygserver_shm.h147
-rwxr-xr-xwinsup/cygwin/cygserver_transport_pipes.cc362
-rw-r--r--winsup/cygwin/cygthread.h2
-rw-r--r--winsup/cygwin/dlmalloc.c3894
-rw-r--r--winsup/cygwin/dlmalloc.h93
-rw-r--r--winsup/cygwin/exceptions.cc58
-rw-r--r--winsup/cygwin/fhandler.cc2
-rw-r--r--winsup/cygwin/heap.cc3
-rw-r--r--winsup/cygwin/include/cygwin/version.h2
-rw-r--r--winsup/cygwin/include/sys/cygwin.h6
-rw-r--r--winsup/cygwin/libc/fnmatch.c220
-rw-r--r--winsup/cygwin/malloc.cc2
-rw-r--r--winsup/cygwin/miscfuncs.cc30
-rw-r--r--winsup/cygwin/net.cc383
-rw-r--r--winsup/cygwin/path.cc5
-rw-r--r--winsup/cygwin/pinfo.h7
-rw-r--r--winsup/cygwin/shm.cc2
-rw-r--r--winsup/cygwin/signal.cc6
-rw-r--r--winsup/cygwin/sigproc.cc247
-rw-r--r--winsup/cygwin/sigproc.h9
-rwxr-xr-xwinsup/cygwin/speclib2
-rw-r--r--winsup/cygwin/wincap.cc36
-rw-r--r--winsup/cygwin/wincap.h2
33 files changed, 4789 insertions, 2626 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index fa3cfa23546..a1e8650512c 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,154 @@
+2003-09-01 Christopher Faylor <cgf@redhat.com>
+
+ * include/cygwin/version.h: Bump DLL minor number to 4.
+
+2003-09-01 Christopher Faylor <cgf@redhat.com>
+
+ * net.cc (dup_ent): Restore check for NULL input.
+
+2003-08-31 Christopher Faylor <cgf@redhat.com>
+
+ * include/sys/cygwin.h: Don't define cygwin-specific things if
+ !__CYGWIN__.
+
+2003-08-31 Christopher Faylor <cgf@redhat.com>
+
+ * cygheap.cc (cygheap_init): Allocate space for sigaction array in
+ cygheap.
+ * cygheap.h (cygheap_types): Add HEAP_SIGS.
+ * exceptions.cc (signal_fixup_after_exec): Remove from this file.
+ * pinfo.h (pinfo::getsig): Just return global_sigs array.
+ (pinfo::sigs): Delete.
+ * sigproc.cc (signal_fixup_after_exec): Move it here.
+ (global_sigs): New global array, moved from pinfo structure.
+ (sigalloc): New function. Allocate global sigaction array here.
+ (proc_subproc): Remove copysigs call. It's automatic now.
+ * include/sys/cygwin.h (PID_NOCLDSTOP): New value.
+ * signal.cc (sigaction): Set myself->PID_NODCLDSTOP when appropriate.
+ * sigproc.h (sigalloc): Declare.
+
+ * fnmatch.c (fnmatch): Use C90 parameters.
+ (rangematch): Ditto.
+
+ * fhandler.cc (fhandler_base::raw_read): Use right coercion to avoid a
+ compiler warning.
+
+2003-08-31 Christopher Faylor <cgf@redhat.com>
+
+ * net.cc (dup_ent): Make debugging output consistent.
+
+2003-08-31 Christopher Faylor <cgf@redhat.com>
+
+ Use dup_ent rather than specific dup_*_ptr functions throughout.
+ * (gen_ent): Delete.
+ (dup_ent): Subsume gen_ent functionality.
+ (dup_host_ptr): Delete.
+ (dup_proto_ptr): Ditto.
+ (dup_servent_ptr): Ditto.
+
+2003-08-31 Christopher Faylor <cgf@redhat.com>
+
+ * net.cc (gen_ent): Invert sense of null check so that debug output
+ makes sense.
+
+2003-08-31 Christopher Faylor <cgf@redhat.com>
+
+ * net.cc (free_char_list): Delete.
+ (dup_addr_list): Delete.
+ (dup_char_list): Delete.
+ (free_hostent_ptr): Delete.
+ (free_protoent_ptr): Delete.
+ (free_servent_ptr): Delete.
+ (DWORD_round): New function.
+ (strlen_round): New function. Returns strlen rounded up to word size.
+ (dup_ent): New, generic function to duplicate a {host,proto,serv}ent
+ structure.
+ (gen_ent): New macro. Generates a generic dup_{host,proto,serv}ent_ptr
+ function.
+ (cygwin_getservbyname): Remove call to free_servent_ptr, pass
+ servent_buf to dup_servent_ptr.
+ (cygwin_getservbyport): Ditto.
+ (cygwin_gethostbyname): Ditto for hostent.
+ (cygwin_gethostbyaddr): Ditto.
+ (cygwin_getprotobyname): Ditto for protoent.
+ (cygwin_getprotobynumber): Ditto.
+
+2003-08-31 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (MALLOC_OFILES): Always fill in with correct malloc
+ object.
+ * configure.in: Fill in MALLOC_OFILES with either debugging or regular
+ malloc.
+ * configure: Regenerate.
+ * dlmalloc.c: Make various fruitless changes to attempt to get to work.
+ * dlmalloc.h: Ditto.
+ * malloc.cc (free): Check malloc pool when debugging.
+
+ * path.cc (win32_device_name): Eliminate compiler warning.
+
+ * sigproc.cc (sig_dispatch_pending): Remove use of was_pending. Let
+ thisframe.call_signal_handler decide if handler should be called rather
+ than using bogus was_pending check.
+
+ * exceptions.cc (interrupt_setup): Remove accidentally checked in
+ debugging code.
+
+2003-08-30 Christopher Faylor <cgf@redhat.com>
+
+ * heap.cc (sbrk): Save rounded addess in user_heap_max.
+
+2003-08-30 Christopher Faylor <cgf@redhat.com>
+
+ * sigproc.cc (sig_dispatch_pending): Remove explicit call to
+ thisframe.call_signal_handler.
+
+2003-08-30 Christopher Faylor <cgf@redhat.com>
+
+ Remove some cygserver files.
+
+2003-08-28 Christopher Faylor <cgf@redhat.com>
+
+ * sigproc.h: Make some functions regparm.
+ * sigproc.cc (checkstate): Make regparm.
+ (getevent): Change parameters in declaration, rename from getsem, make regparm.
+ (sig_send): Recognize that nosync is now an event. Remove some old
+ cruft from previous interrupt anywhere signal handler.
+ (getevent): Change parameters in definition, rename from getsem.
+ Allocate event rather than semaphore.
+ (wait_sig): Treat sigcatch_nosync as an event.
+
+2003-08-28 Christopher Faylor <cgf@redhat.com>
+
+ * exceptions.cc (sigreturn): Fix problem where old return address was
+ not properly restored for a nested signal.
+
+2003-08-27 Christopher Faylor <cgf@redhat.com>
+
+ * autoload.cc (SwitchToThread): Declare as autoload function.
+ * cygthread.h (cygthread::main_thread_id): Make public.
+ * exceptions.cc (setup_handler): Remove unneeded priority stuff.
+ Rename label to reflect what it does. Add debugging for idiotic
+ Windows NT problem. Change debugging output to include signal number.
+ * miscfuncs.cc (low_priority_sleep): If available, use SwitchToThread
+ function to give time slice to other threads.
+ * wincap.cc: Properly define have_switch_to_thread throughout.
+ * wincap.h (wincap::switch_to_thread): New element.
+
+2003-08-27 Christopher Faylor <cgf@redhat.com>
+
+ * syscalls.cc (mount): Don't check win32_path when doing cygdrive
+ mount.
+
+2003-08-27 Christopher Faylor <cgf@redhat.com>
+
+ * specdir: Correctly remove temporary directory prior to use.
+
+2003-08-27 Christopher Faylor <cgf@redhat.com>
+
+ * sigproc.cc (wait_sig): Count number of iterations through
+ 'more_signals' loop and issue a warning if DEBUGGING and excessive.
+ (WFSO): When debugging and infinite timeout, loop.
+
2003-08-26 Corinna Vinschen <corinna@vinschen.de>
* include/cygwin/stat.h: Allow definition of internal stat structures
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index cd021353231..d0fc32c7c40 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -154,7 +154,7 @@ DLL_OFILES:=assert.o autoload.o cxx.o cygheap.o cygthread.o dcrt0.o debug.o \
fhandler_socket.o fhandler_tape.o fhandler_termios.o \
fhandler_tty.o fhandler_virtual.o fhandler_windows.o \
fhandler_zero.o fnmatch.o fork.o glob.o grp.o heap.o init.o ioctl.o \
- ipc.o localtime.o malloc.o malloc_wrapper.o miscfuncs.o mmap.o msg.o \
+ ipc.o localtime.o malloc_wrapper.o miscfuncs.o mmap.o msg.o \
net.o netdb.o ntea.o passwd.o path.o pinfo.o pipe.o poll.o pthread.o \
regcomp.o regerror.o regexec.o regfree.o registry.o resource.o \
scandir.o sched.o sec_acl.o sec_helper.o security.o select.o sem.o \
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index f5cc250fa0e..c2c7ae3528b 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -510,6 +510,7 @@ LoadDLLfunc (IsProcessorFeaturePresent, 4, kernel32);
LoadDLLfuncEx (Process32First, 8, kernel32, 1)
LoadDLLfuncEx (Process32Next, 8, kernel32, 1)
LoadDLLfuncEx (SignalObjectAndWait, 16, kernel32, 1)
+LoadDLLfuncEx (SwitchToThread, 0, kernel32, 1)
LoadDLLfunc (TryEnterCriticalSection, 4, kernel32)
LoadDLLfuncEx (waveOutGetNumDevs, 0, winmm, 1)
diff --git a/winsup/cygwin/configure b/winsup/cygwin/configure
index 3500fad387c..eb1b6889a1b 100755
--- a/winsup/cygwin/configure
+++ b/winsup/cygwin/configure
@@ -1916,7 +1916,7 @@ esac
fi
-MALLOC_OFILES=
+MALLOC_OFILES=malloc.o
# Check whether --enable-malloc-debugging or --disable-malloc-debugging was given.
if test "${enable_malloc_debugging+set}" = set; then
enableval="$enable_malloc_debugging"
diff --git a/winsup/cygwin/configure.in b/winsup/cygwin/configure.in
index c0ad97682dc..d47b4084fda 100644
--- a/winsup/cygwin/configure.in
+++ b/winsup/cygwin/configure.in
@@ -145,7 +145,7 @@ no) LIBSERVER=;;
esac
])
-MALLOC_OFILES=
+MALLOC_OFILES=malloc.o
AC_ARG_ENABLE(malloc-debugging,
[ --enable-malloc-debugging Build a cygwin DLL with heap sanity checking (this is very slow, use only if you have heap corruption problems)],
[case "${enableval}" in
diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc
index c18232eed82..f681a5ca2b3 100644
--- a/winsup/cygwin/cygheap.cc
+++ b/winsup/cygwin/cygheap.cc
@@ -22,6 +22,7 @@
#include "heap.h"
#include "sync.h"
#include "shared_info.h"
+#include "sigproc.h"
init_cygheap NO_COPY *cygheap;
void NO_COPY *cygheap_max;
@@ -203,6 +204,8 @@ cygheap_init ()
}
if (!cygheap->fdtab)
cygheap->fdtab.init ();
+ if (!cygheap->sigs)
+ sigalloc ();
}
/* Copyright (C) 1997, 2000 DJ Delorie */
diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h
index 0d30f1cceca..6939507a53c 100644
--- a/winsup/cygwin/cygheap.h
+++ b/winsup/cygwin/cygheap.h
@@ -17,6 +17,7 @@ enum cygheap_types
HEAP_ARGV,
HEAP_BUF,
HEAP_MOUNT,
+ HEAP_SIGS,
HEAP_1_START,
HEAP_1_STR,
HEAP_1_ARGV,
@@ -255,6 +256,7 @@ struct init_cygheap
#ifdef DEBUGGING
cygheap_debug debug;
#endif
+ struct sigaction *sigs;
};
#define CYGHEAPSIZE (sizeof (init_cygheap) + (16000 * sizeof (fhandler_union)) + (5 * 65536))
diff --git a/winsup/cygwin/cygserver.cc b/winsup/cygwin/cygserver.cc
deleted file mode 100755
index 137730f9ef7..00000000000
--- a/winsup/cygwin/cygserver.cc
+++ /dev/null
@@ -1,773 +0,0 @@
-/* cygserver.cc
-
- Copyright 2001, 2002 Red Hat Inc.
-
- Written by Egor Duda <deo@logos-m.ru>
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-#include "woutsup.h"
-
-#include <sys/types.h>
-
-#include <assert.h>
-#include <ctype.h>
-#include <getopt.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "cygerrno.h"
-#include "cygwin_version.h"
-
-#include "cygwin/cygserver.h"
-#include "cygwin/cygserver_process.h"
-#include "cygwin/cygserver_transport.h"
-
-// Version string.
-static const char version[] = "$Revision$";
-
-/*
- * Support function for the XXX_printf () macros in "woutsup.h".
- * Copied verbatim from "strace.cc".
- */
-static int
-getfunc (char *in_dst, const char *func)
-{
- const char *p;
- const char *pe;
- char *dst = in_dst;
- for (p = func; (pe = strchr (p, '(')); p = pe + 1)
- if (isalnum ((int)pe[-1]) || pe[-1] == '_')
- break;
- else if (isspace ((int)pe[-1]))
- {
- pe--;
- break;
- }
- if (!pe)
- pe = strchr (func, '\0');
- for (p = pe; p > func; p--)
- if (p != pe && *p == ' ')
- {
- p++;
- break;
- }
- if (*p == '*')
- p++;
- while (p < pe)
- *dst++ = *p++;
-
- *dst++ = ':';
- *dst++ = ' ';
- *dst = '\0';
-
- return dst - in_dst;
-}
-
-/*
- * Support function for the XXX_printf () macros in "woutsup.h".
- */
-extern "C" void
-__cygserver__printf (const char *const function, const char *const fmt, ...)
-{
- const DWORD lasterror = GetLastError ();
- const int lasterrno = errno;
-
- va_list ap;
-
- char *const buf = (char *) alloca (BUFSIZ);
-
- assert (buf);
-
- int len = 0;
-
- if (function)
- len += getfunc (buf, function);
-
- va_start (ap, fmt);
- len += vsnprintf (buf + len, BUFSIZ - len, fmt, ap);
- va_end (ap);
-
- len += snprintf (buf + len, BUFSIZ - len, "\n");
-
- const int actual = (len > BUFSIZ ? BUFSIZ : len);
-
- write (2, buf, actual);
-
- errno = lasterrno;
- SetLastError (lasterror);
-
- return;
-}
-
-#ifdef DEBUGGING
-
-int __stdcall
-__set_errno (const char *func, int ln, int val)
-{
- debug_printf ("%s:%d val %d", func, ln, val);
- return _impure_ptr->_errno = val;
-}
-
-#endif /* DEBUGGING */
-
-GENERIC_MAPPING access_mapping;
-
-static BOOL
-setup_privileges ()
-{
- BOOL rc, ret_val;
- HANDLE hToken = NULL;
- TOKEN_PRIVILEGES sPrivileges;
-
- rc = OpenProcessToken (GetCurrentProcess () , TOKEN_ALL_ACCESS , &hToken) ;
- if (!rc)
- {
- system_printf ("error opening process token (%lu)", GetLastError ());
- ret_val = FALSE;
- goto out;
- }
- rc = LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &sPrivileges.Privileges[0].Luid);
- if (!rc)
- {
- system_printf ("error getting privilege luid (%lu)", GetLastError ());
- ret_val = FALSE;
- goto out;
- }
- sPrivileges.PrivilegeCount = 1 ;
- sPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED ;
- rc = AdjustTokenPrivileges (hToken, FALSE, &sPrivileges, 0, NULL, NULL) ;
- if (!rc)
- {
- system_printf ("error adjusting privilege level. (%lu)",
- GetLastError ());
- ret_val = FALSE;
- goto out;
- }
-
- access_mapping.GenericRead = FILE_READ_DATA;
- access_mapping.GenericWrite = FILE_WRITE_DATA;
- access_mapping.GenericExecute = 0;
- access_mapping.GenericAll = FILE_READ_DATA | FILE_WRITE_DATA;
-
- ret_val = TRUE;
-
-out:
- CloseHandle (hToken);
- return ret_val;
-}
-
-int
-check_and_dup_handle (HANDLE from_process, HANDLE to_process,
- HANDLE from_process_token,
- DWORD access,
- HANDLE from_handle,
- HANDLE *to_handle_ptr, BOOL bInheritHandle = FALSE)
-{
- HANDLE local_handle = NULL;
- int ret_val = EACCES;
-
- if (from_process != GetCurrentProcess ())
- {
- if (!DuplicateHandle (from_process, from_handle,
- GetCurrentProcess (), &local_handle,
- 0, bInheritHandle,
- DUPLICATE_SAME_ACCESS))
- {
- system_printf ("error getting handle(%u) to server (%lu)",
- (unsigned int)from_handle, GetLastError ());
- goto out;
- }
- } else
- local_handle = from_handle;
-
- if (!wincap.has_security ())
- assert (!from_process_token);
- else
- {
- char sd_buf [1024];
- PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR) &sd_buf;
- DWORD bytes_needed;
- PRIVILEGE_SET ps;
- DWORD ps_len = sizeof (ps);
- BOOL status;
-
- if (!GetKernelObjectSecurity (local_handle,
- (OWNER_SECURITY_INFORMATION
- | GROUP_SECURITY_INFORMATION
- | DACL_SECURITY_INFORMATION),
- sd, sizeof (sd_buf), &bytes_needed))
- {
- system_printf ("error getting handle SD (%lu)", GetLastError ());
- goto out;
- }
-
- MapGenericMask (&access, &access_mapping);
-
- if (!AccessCheck (sd, from_process_token, access, &access_mapping,
- &ps, &ps_len, &access, &status))
- {
- system_printf ("error checking access rights (%lu)",
- GetLastError ());
- goto out;
- }
-
- if (!status)
- {
- system_printf ("access to object denied");
- goto out;
- }
- }
-
- if (!DuplicateHandle (from_process, from_handle,
- to_process, to_handle_ptr,
- access, bInheritHandle, 0))
- {
- system_printf ("error getting handle to client (%lu)", GetLastError ());
- goto out;
- }
-
- // verbose: debug_printf ("Duplicated %p to %p", from_handle, *to_handle_ptr);
-
- ret_val = 0;
-
- out:
- if (local_handle && from_process != GetCurrentProcess ())
- CloseHandle (local_handle);
-
- return (ret_val);
-}
-
-/*
- * client_request_attach_tty::serve ()
- */
-
-void
-client_request_attach_tty::serve (transport_layer_base *const conn,
- process_cache *)
-{
- assert (conn);
-
- assert (!error_code ());
-
- if (!wincap.has_security ())
- {
- syscall_printf ("operation only supported on systems with security");
- error_code (EINVAL);
- msglen (0);
- return;
- }
-
- if (msglen () != sizeof (req))
- {
- syscall_printf ("bad request body length: expecting %lu bytes, got %lu",
- sizeof (req), msglen ());
- error_code (EINVAL);
- msglen (0);
- return;
- }
-
- msglen (0); // Until we fill in some fields.
-
- // verbose: debug_printf ("pid %ld:(%p,%p) -> pid %ld",
- // req.master_pid, req.from_master, req.to_master,
- // req.pid);
-
- // verbose: debug_printf ("opening process %ld", req.master_pid);
-
- const HANDLE from_process_handle =
- OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.master_pid);
-
- if (!from_process_handle)
- {
- system_printf ("error opening `from' process, error = %lu",
- GetLastError ());
- error_code (EACCES);
- return;
- }
-
- // verbose: debug_printf ("opening process %ld", req.pid);
-
- const HANDLE to_process_handle =
- OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.pid);
-
- if (!to_process_handle)
- {
- system_printf ("error opening `to' process, error = %lu",
- GetLastError ());
- CloseHandle (from_process_handle);
- error_code (EACCES);
- return;
- }
-
- // verbose: debug_printf ("Impersonating client");
- conn->impersonate_client ();
-
- HANDLE token_handle = NULL;
-
- // verbose: debug_printf ("about to open thread token");
- const DWORD rc = OpenThreadToken (GetCurrentThread (),
- TOKEN_QUERY,
- TRUE,
- &token_handle);
-
- // verbose: debug_printf ("opened thread token, rc=%lu", rc);
- conn->revert_to_self ();
-
- if (!rc)
- {
- system_printf ("error opening thread token, error = %lu",
- GetLastError ());
- CloseHandle (from_process_handle);
- CloseHandle (to_process_handle);
- error_code (EACCES);
- return;
- }
-
- // From this point on, a reply body is returned to the client.
-
- const HANDLE from_master = req.from_master;
- const HANDLE to_master = req.to_master;
-
- req.from_master = NULL;
- req.to_master = NULL;
-
- msglen (sizeof (req));
-
- if (from_master)
- if (check_and_dup_handle (from_process_handle, to_process_handle,
- token_handle,
- GENERIC_READ,
- from_master,
- &req.from_master, TRUE) != 0)
- {
- system_printf ("error duplicating from_master handle, error = %lu",
- GetLastError ());
- error_code (EACCES);
- }
-
- if (to_master)
- if (check_and_dup_handle (from_process_handle, to_process_handle,
- token_handle,
- GENERIC_WRITE,
- to_master,
- &req.to_master, TRUE) != 0)
- {
- system_printf ("error duplicating to_master handle, error = %lu",
- GetLastError ());
- error_code (EACCES);
- }
-
- CloseHandle (from_process_handle);
- CloseHandle (to_process_handle);
- CloseHandle (token_handle);
-
- debug_printf ("%lu(%lu, %lu) -> %lu(%lu,%lu)",
- req.master_pid, from_master, to_master,
- req.pid, req.from_master, req.to_master);
-
- return;
-}
-
-void
-client_request_get_version::serve (transport_layer_base *, process_cache *)
-{
- assert (!error_code ());
-
- if (msglen ())
- syscall_printf ("unexpected request body ignored: %lu bytes", msglen ());
-
- msglen (sizeof (version));
-
- version.major = CYGWIN_SERVER_VERSION_MAJOR;
- version.api = CYGWIN_SERVER_VERSION_API;
- version.minor = CYGWIN_SERVER_VERSION_MINOR;
- version.patch = CYGWIN_SERVER_VERSION_PATCH;
-}
-
-class server_request : public queue_request
-{
-public:
- server_request (transport_layer_base *const conn, process_cache *const cache)
- : _conn (conn), _cache (cache)
- {}
-
- virtual ~server_request ()
- {
- safe_delete (_conn);
- }
-
- virtual void process ()
- {
- client_request::handle_request (_conn, _cache);
- }
-
-private:
- transport_layer_base *const _conn;
- process_cache *const _cache;
-};
-
-class server_submission_loop : public queue_submission_loop
-{
-public:
- server_submission_loop (threaded_queue *const queue,
- transport_layer_base *const transport,
- process_cache *const cache)
- : queue_submission_loop (queue, false),
- _transport (transport),
- _cache (cache)
- {
- assert (_transport);
- assert (_cache);
- }
-
-private:
- transport_layer_base *const _transport;
- process_cache *const _cache;
-
- virtual void request_loop ();
-};
-
-/* FIXME: this is a little ugly. What we really want is to wait on
- * two objects: one for the pipe/socket, and one for being told to
- * shutdown. Otherwise this will stay a problem (we won't actually
- * shutdown until the request _AFTER_ the shutdown request. And
- * sending ourselves a request is ugly
- */
-void
-server_submission_loop::request_loop ()
-{
- /* I'd like the accepting thread's priority to be above any "normal"
- * thread in the system to avoid overflowing the listen queue (for
- * sockets; similar issues exist for named pipes); but, for example,
- * a normal priority thread in a foregrounded process is boosted to
- * THREAD_PRIORITY_HIGHEST (AFAICT). Thus try to set the current
- * thread's priority to a level one above that. This fails on
- * win9x/ME so assume any failure in that call is due to that and
- * simply call again at one priority level lower.
- */
- if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST + 1))
- if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST))
- debug_printf ("failed to raise accept thread priority, error = %lu",
- GetLastError ());
-
- while (_running)
- {
- bool recoverable = false;
- transport_layer_base *const conn = _transport->accept (&recoverable);
- if (!conn && !recoverable)
- {
- system_printf ("fatal error on IPC transport: closing down");
- return;
- }
- // EINTR probably implies a shutdown request; so back off for a
- // moment to let the main thread take control, otherwise the
- // server spins here receiving EINTR repeatedly since the signal
- // handler in the main thread doesn't get a chance to be called.
- if (!conn && errno == EINTR)
- {
- if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL))
- debug_printf ("failed to reset thread priority, error = %lu",
- GetLastError ());
-
- Sleep (0);
- if (!SetThreadPriority (GetCurrentThread (),
- THREAD_PRIORITY_HIGHEST + 1))
- if (!SetThreadPriority (GetCurrentThread (),
- THREAD_PRIORITY_HIGHEST))
- debug_printf ("failed to raise thread priority, error = %lu",
- GetLastError ());
- }
- if (conn)
- _queue->add (safe_new (server_request, conn, _cache));
- }
-}
-
-client_request_shutdown::client_request_shutdown ()
- : client_request (CYGSERVER_REQUEST_SHUTDOWN)
-{
- // verbose: syscall_printf ("created");
-}
-
-void
-client_request_shutdown::serve (transport_layer_base *, process_cache *)
-{
- assert (!error_code ());
-
- if (msglen ())
- syscall_printf ("unexpected request body ignored: %lu bytes", msglen ());
-
- /* FIXME: link upwards, and then this becomes a trivial method call to
- * only shutdown _this queue_
- */
-
- kill (getpid (), SIGINT);
-
- msglen (0);
-}
-
-static sig_atomic_t shutdown_server = false;
-
-static void
-handle_signal (const int signum)
-{
- /* any signal makes us die :} */
-
- shutdown_server = true;
-}
-
-/*
- * print_usage ()
- */
-
-static void
-print_usage (const char *const pgm)
-{
- printf ("Usage: %s [OPTIONS]\n", pgm);
- printf (" -c, --cleanup-threads number of cleanup threads to use\n");
- printf (" -h, --help output usage information and exit\n");
- printf (" -r, --request-threads number of request threads to use\n");
- printf (" -s, --shutdown shutdown the daemon\n");
- printf (" -v, --version output version information and exit\n");
-}
-
-/*
- * print_version ()
- */
-
-static void
-print_version (const char *const pgm)
-{
- char *vn = NULL;
-
- const char *const colon = strchr (version, ':');
-
- if (!colon)
- {
- vn = strdup ("?");
- }
- else
- {
- vn = strdup (colon + 2); // Skip ": "
-
- char *const spc = strchr (vn, ' ');
-
- if (spc)
- *spc = '\0';
- }
-
- char buf[200];
- snprintf (buf, sizeof (buf), "%d.%d.%d(%d.%d/%d/%d)-(%d.%d.%d.%d) %s",
- cygwin_version.dll_major / 1000,
- cygwin_version.dll_major % 1000,
- cygwin_version.dll_minor,
- cygwin_version.api_major,
- cygwin_version.api_minor,
- cygwin_version.shared_data,
- CYGWIN_SERVER_VERSION_MAJOR,
- CYGWIN_SERVER_VERSION_API,
- CYGWIN_SERVER_VERSION_MINOR,
- CYGWIN_SERVER_VERSION_PATCH,
- cygwin_version.mount_registry,
- cygwin_version.dll_build_date);
-
- printf ("%s (cygwin) %s\n", pgm, vn);
- printf ("API version %s\n", buf);
- printf ("Copyright 2001, 2002 Red Hat, Inc.\n");
- printf ("Compiled on %s\n", __DATE__);
-
- free (vn);
-}
-
-/*
- * main ()
- */
-
-int
-main (const int argc, char *argv[])
-{
- const struct option longopts[] = {
- {"cleanup-threads", required_argument, NULL, 'c'},
- {"help", no_argument, NULL, 'h'},
- {"request-threads", required_argument, NULL, 'r'},
- {"shutdown", no_argument, NULL, 's'},
- {"version", no_argument, NULL, 'v'},
- {0, no_argument, NULL, 0}
- };
-
- const char opts[] = "c:hr:sv";
-
- int cleanup_threads = 2;
- int request_threads = 10;
- bool shutdown = false;
-
- const char *pgm = NULL;
-
- if (!(pgm = strrchr (*argv, '\\')) && !(pgm = strrchr (*argv, '/')))
- pgm = *argv;
- else
- pgm++;
-
- wincap.init ();
- if (wincap.has_security ())
- setup_privileges ();
-
- int opt;
-
- while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
- switch (opt)
- {
- case 'c':
- cleanup_threads = atoi (optarg);
- if (cleanup_threads <= 0)
- {
- fprintf (stderr,
- "%s: number of cleanup threads must be positive\n",
- pgm);
- exit (1);
- }
- break;
-
- case 'h':
- print_usage (pgm);
- return 0;
-
- case 'r':
- request_threads = atoi (optarg);
- if (request_threads <= 0)
- {
- fprintf (stderr,
- "%s: number of request threads must be positive\n",
- pgm);
- exit (1);
- }
- break;
-
- case 's':
- shutdown = true;
- break;
-
- case 'v':
- print_version (pgm);
- return 0;
-
- case '?':
- fprintf (stderr, "Try `%s --help' for more information.\n", pgm);
- exit (1);
- }
-
- if (optind != argc)
- {
- fprintf (stderr, "%s: too many arguments\n", pgm);
- exit (1);
- }
-
- if (shutdown)
- {
- /* Setting `cygserver_running' stops the request code making a
- * version request, which is not much to the point.
- */
- cygserver_running = CYGSERVER_OK;
-
- client_request_shutdown req;
-
- if (req.make_request () == -1 || req.error_code ())
- {
- fprintf (stderr, "%s: shutdown request failed: %s\n",
- pgm, strerror (req.error_code ()));
- exit (1);
- }
-
- // FIXME: It would be nice to wait here for the daemon to exit.
-
- return 0;
- }
-
-#define SIGHANDLE(SIG) \
- do \
- { \
- struct sigaction act; \
- \
- act.sa_handler = &handle_signal; \
- act.sa_mask = 0; \
- act.sa_flags = 0; \
- \
- if (sigaction (SIG, &act, NULL) == -1) \
- { \
- system_printf ("failed to install handler for " #SIG ": %s", \
- strerror (errno)); \
- exit (1); \
- } \
- } while (false)
-
- SIGHANDLE (SIGHUP);
- SIGHANDLE (SIGINT);
- SIGHANDLE (SIGTERM);
-
- print_version (pgm);
- setbuf (stdout, NULL);
- printf ("daemon starting up");
-
- threaded_queue request_queue (request_threads);
- printf (".");
-
- transport_layer_base *const transport = create_server_transport ();
- assert (transport);
- printf (".");
-
- process_cache cache (cleanup_threads);
- printf (".");
-
- server_submission_loop submission_loop (&request_queue, transport, &cache);
- printf (".");
-
- request_queue.add_submission_loop (&submission_loop);
- printf (".");
-
- if (transport->listen () == -1)
- {
- exit (1);
- }
- printf (".");
-
- cache.start ();
- printf (".");
-
- request_queue.start ();
- printf (".");
-
- printf ("complete\n");
-
- /* TODO: wait on multiple objects - the thread handle for each
- * request loop + all the process handles. This should be done by
- * querying the request_queue and the process cache for all their
- * handles, and then waiting for (say) 30 seconds. after that we
- * recreate the list of handles to wait on, and wait again. the
- * point of all this abstraction is that we can trivially server
- * both sockets and pipes simply by making a new transport, and then
- * calling request_queue.process_requests (transport2);
- */
- /* WaitForMultipleObjects abort && request_queue && process_queue && signal
- -- if signal event then retrigger it
- */
- while (!shutdown_server && request_queue.running () && cache.running ())
- pause ();
-
- printf ("\nShutdown request received - new requests will be denied\n");
- request_queue.stop ();
- printf ("All pending requests processed\n");
- safe_delete (transport);
- printf ("No longer accepting requests - cygwin will operate in daemonless mode\n");
- cache.stop ();
- printf ("All outstanding process-cache activities completed\n");
- printf ("daemon shutdown\n");
-
- return 0;
-}
diff --git a/winsup/cygwin/cygserver_client.cc b/winsup/cygwin/cygserver_client.cc
deleted file mode 100755
index f6683182d72..00000000000
--- a/winsup/cygwin/cygserver_client.cc
+++ /dev/null
@@ -1,528 +0,0 @@
-/* cygserver_client.cc
-
- Copyright 2001, 2002 Red Hat Inc.
-
- Written by Egor Duda <deo@logos-m.ru>
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-/* to allow this to link into cygwin and the .dll, a little magic is needed. */
-#ifdef __OUTSIDE_CYGWIN__
-#include "woutsup.h"
-#else
-#include "winsup.h"
-#endif
-
-#include <assert.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include "cygerrno.h"
-#include "cygserver_shm.h"
-#include "safe_memory.h"
-
-#include "cygwin/cygserver.h"
-#include "cygwin/cygserver_transport.h"
-
-int cygserver_running = CYGSERVER_UNKNOWN; // Nb: inherited by children.
-
-/* On by default during development. For release, we probably want off
- * by default.
- */
-bool allow_daemon = true; // Nb: inherited by children.
-
-client_request_get_version::client_request_get_version ()
- : client_request (CYGSERVER_REQUEST_GET_VERSION, &version, sizeof (version))
-{
- msglen (0); // No parameters for request.
-
- // verbose: syscall_printf ("created");
-}
-
-/*
- * client_request_get_version::check_version ()
- *
- * The major version and API version numbers must match exactly. An
- * older than expected minor version number is accepted (as long as
- * the first numbers match, that is).
- */
-
-bool
-client_request_get_version::check_version () const
-{
- const bool ok = (version.major == CYGWIN_SERVER_VERSION_MAJOR
- && version.api == CYGWIN_SERVER_VERSION_API
- && version.minor <= CYGWIN_SERVER_VERSION_MINOR);
-
- if (!ok)
- syscall_printf (("incompatible version of cygwin server: "
- "client version %d.%d.%d.%d, "
- "server version %ld.%ld.%ld.%ld"),
- CYGWIN_SERVER_VERSION_MAJOR,
- CYGWIN_SERVER_VERSION_API,
- CYGWIN_SERVER_VERSION_MINOR,
- CYGWIN_SERVER_VERSION_PATCH,
- version.major,
- version.api,
- version.minor,
- version.patch);
-
- return ok;
-}
-
-#ifdef __INSIDE_CYGWIN__
-
-client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid,
- HANDLE nfrom_master,
- HANDLE nto_master)
- : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
-{
- req.pid = GetCurrentProcessId ();
- req.master_pid = nmaster_pid;
- req.from_master = nfrom_master;
- req.to_master = nto_master;
-
- syscall_printf (("created: pid = %lu, master_pid = %lu, "
- "from_master = %lu, to_master = %lu"),
- req.pid, req.master_pid, req.from_master, req.to_master);
-}
-
-#else /* !__INSIDE_CYGWIN__ */
-
-client_request_attach_tty::client_request_attach_tty ()
- : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
-{
- // verbose: syscall_printf ("created");
-}
-
-#endif /* __INSIDE_CYGWIN__ */
-
-/*
- * client_request_attach_tty::send ()
- *
- * Wraps the base method to provide error handling support. If the
- * reply contains a body but is flagged as an error, close any handles
- * that have been returned by cygserver and then discard the message
- * body, i.e. the client either sees a successful result with handles
- * or an unsuccessful result with no handles.
- */
-
-void
-client_request_attach_tty::send (transport_layer_base * const conn)
-{
- client_request::send (conn);
-
- if (msglen () && error_code ())
- {
- if (from_master ())
- CloseHandle (from_master ());
- if (to_master ())
- CloseHandle (to_master ());
- msglen (0);
- }
-}
-
-client_request::header_t::header_t (const request_code_t request_code,
- const size_t msglen)
- : msglen (msglen),
- request_code (request_code)
-{
- assert (request_code >= 0 && request_code < CYGSERVER_REQUEST_LAST);
-}
-
-// FIXME: also check write and read result for -1.
-
-void
-client_request::send (transport_layer_base * const conn)
-{
- assert (conn);
- assert (!(msglen () && !_buf)); // i.e., msglen () implies _buf
- assert (msglen () <= _buflen);
-
- {
- const ssize_t count = conn->write (&_header, sizeof (_header));
-
- if (count != sizeof (_header))
- {
- assert (errno);
- error_code (errno);
- syscall_printf (("request header write failure: "
- "only %ld bytes sent of %ld, "
- "error = %d(%lu)"),
- count, sizeof (_header),
- errno, GetLastError ());
- return;
- }
- }
-
- if (msglen ())
- {
- const ssize_t count = conn->write (_buf, msglen ());
-
- if (count == -1 || (size_t) count != msglen ())
- {
- assert (errno);
- error_code (errno);
- syscall_printf (("request body write failure: "
- "only %ld bytes sent of %ld, "
- "error = %d(%lu)"),
- count, msglen (),
- errno, GetLastError ());
- return;
- }
- }
-
- // verbose: syscall_printf ("request sent (%ld + %ld bytes)",
- // sizeof (_header), msglen ());
-
- {
- const ssize_t count = conn->read (&_header, sizeof (_header));
-
- if (count != sizeof (_header))
- {
- assert (errno);
- error_code (errno);
- syscall_printf (("reply header read failure: "
- "only %ld bytes received of %ld, "
- "error = %d(%lu)"),
- count, sizeof (_header),
- errno, GetLastError ());
- return;
- }
- }
-
- if (msglen () && !_buf)
- {
- system_printf ("no client buffer for reply body: %ld bytes needed",
- msglen ());
- error_code (EINVAL);
- return;
- }
-
- if (msglen () > _buflen)
- {
- system_printf (("client buffer too small for reply body: "
- "have %ld bytes and need %ld"),
- _buflen, msglen ());
- error_code (EINVAL);
- return;
- }
-
- if (msglen ())
- {
- const ssize_t count = conn->read (_buf, msglen ());
-
- if (count == -1 || (size_t) count != msglen ())
- {
- assert (errno);
- error_code (errno);
- syscall_printf (("reply body read failure: "
- "only %ld bytes received of %ld, "
- "error = %d(%lu)"),
- count, msglen (),
- errno, GetLastError ());
- return;
- }
- }
-
- // verbose: syscall_printf ("reply received (%ld + %ld bytes)",
- // sizeof (_header), msglen ());
-}
-
-#ifndef __INSIDE_CYGWIN__
-
-/*
- * client_request::handle_request ()
- *
- * A server-side method.
- *
- * This is a factory method for the client_request subclasses. It
- * reads the incoming request header and, based on its request code,
- * creates an instance of the appropriate class.
- *
- * FIXME: If the incoming packet is malformed, the server drops it on
- * the floor. Should it try and generate some sort of reply for the
- * client? As it is, the client will simply get a broken connection.
- *
- * FIXME: also check write and read result for -1.
- */
-
-/* static */ void
-client_request::handle_request (transport_layer_base *const conn,
- process_cache *const cache)
-{
- // verbose: debug_printf ("about to read");
-
- header_t header;
-
- {
- const ssize_t count = conn->read (&header, sizeof (header));
-
- if (count != sizeof (header))
- {
- syscall_printf (("request header read failure: "
- "only %ld bytes received of %ld, "
- "error = %d(%lu)"),
- count, sizeof (header),
- errno, GetLastError ());
- return;
- }
-
- // verbose: debug_printf ("got header (%ld)", count);
- }
-
- client_request *req = NULL;
-
- switch (header.request_code)
- {
- case CYGSERVER_REQUEST_GET_VERSION:
- req = safe_new0 (client_request_get_version);
- break;
- case CYGSERVER_REQUEST_SHUTDOWN:
- req = safe_new0 (client_request_shutdown);
- break;
- case CYGSERVER_REQUEST_ATTACH_TTY:
- req = safe_new0 (client_request_attach_tty);
- break;
- case CYGSERVER_REQUEST_SHM:
- req = safe_new0 (client_request_shm);
- break;
- default:
- syscall_printf ("unknown request code %d received: request ignored",
- header.request_code);
- return;
- }
-
- assert (req);
-
- req->msglen (header.msglen);
- req->handle (conn, cache);
-
- safe_delete (req);
-
-#ifndef DEBUGGING
- printf ("."); // A little noise when we're being quiet.
-#endif
-}
-
-#endif /* !__INSIDE_CYGWIN__ */
-
-client_request::client_request (request_code_t const id,
- void * const buf,
- size_t const buflen)
- : _header (id, buflen),
- _buf (buf),
- _buflen (buflen)
-{
- assert ((!_buf && !_buflen) || (_buf && _buflen));
-}
-
-client_request::~client_request ()
-{}
-
-int
-client_request::make_request ()
-{
- assert (cygserver_running == CYGSERVER_UNKNOWN \
- || cygserver_running == CYGSERVER_OK \
- || cygserver_running == CYGSERVER_UNAVAIL);
-
- if (cygserver_running == CYGSERVER_UNKNOWN)
- cygserver_init ();
-
- assert (cygserver_running == CYGSERVER_OK \
- || cygserver_running == CYGSERVER_UNAVAIL);
-
- /* Don't retry every request if the server's not there */
- if (cygserver_running == CYGSERVER_UNAVAIL)
- {
- syscall_printf ("cygserver un-available");
- error_code (ENOSYS);
- return -1;
- }
-
- transport_layer_base *const transport = create_server_transport ();
-
- assert (transport);
-
- if (transport->connect () == -1)
- {
- if (errno)
- error_code (errno);
- else
- error_code (ENOSYS);
- safe_delete (transport);
- return -1;
- }
-
- // verbose: debug_printf ("connected to server %p", transport);
-
- send (transport);
-
- safe_delete (transport);
-
- return 0;
-}
-
-#ifndef __INSIDE_CYGWIN__
-
-/*
- * client_request::handle ()
- *
- * A server-side method.
- *
- * At this point, the header of an incoming request has been read and
- * an appropriate client_request object constructed. This method has
- * to read the request body into its buffer, if there is such a body,
- * then perform the request and send back the results to the client.
- *
- * FIXME: If the incoming packet is malformed, the server drops it on
- * the floor. Should it try and generate some sort of reply for the
- * client? As it is, the client will simply get a broken connection.
- *
- * FIXME: also check write and read result for -1.
- */
-
-void
-client_request::handle (transport_layer_base *const conn,
- process_cache *const cache)
-{
- if (msglen () && !_buf)
- {
- system_printf ("no buffer for request body: %ld bytes needed",
- msglen ());
- error_code (EINVAL);
- return;
- }
-
- if (msglen () > _buflen)
- {
- system_printf (("buffer too small for request body: "
- "have %ld bytes and need %ld"),
- _buflen, msglen ());
- error_code (EINVAL);
- return;
- }
-
- if (msglen ())
- {
- const ssize_t count = conn->read (_buf, msglen ());
-
- if (count == -1 || (size_t) count != msglen ())
- {
- assert (errno);
- error_code (errno);
- syscall_printf (("request body read failure: "
- "only %ld bytes received of %ld, "
- "error = %d(%lu)"),
- count, msglen (),
- errno, GetLastError ());
- return;
- }
- }
-
- // verbose: syscall_printf ("request received (%ld + %ld bytes)",
- // sizeof (_header), msglen ());
-
- error_code (0); // Overwrites the _header.request_code field.
-
- /*
- * This is not allowed to fail. We must return ENOSYS at a minimum
- * to the client.
- */
- serve (conn, cache);
-
- {
- const ssize_t count = conn->write (&_header, sizeof (_header));
-
- if (count != sizeof (_header))
- {
- assert (errno);
- error_code (errno);
- syscall_printf (("reply header write failure: "
- "only %ld bytes sent of %ld, "
- "error = %d(%lu)"),
- count, sizeof (_header),
- errno, GetLastError ());
- return;
- }
- }
-
- if (msglen ())
- {
- const ssize_t count = conn->write (_buf, msglen ());
-
- if (count == -1 || (size_t) count != msglen ())
- {
- assert (errno);
- error_code (errno);
- syscall_printf (("reply body write failure: "
- "only %ld bytes sent of %ld, "
- "error = %d(%lu)"),
- count, msglen (),
- errno, GetLastError ());
- return;
- }
- }
-
- // verbose: syscall_printf ("reply sent (%ld + %ld bytes)",
- // sizeof (_header), msglen ());
-}
-
-#endif /* !__INSIDE_CYGWIN__ */
-
-bool
-check_cygserver_available ()
-{
- assert (cygserver_running == CYGSERVER_UNKNOWN \
- || cygserver_running == CYGSERVER_UNAVAIL);
-
- cygserver_running = CYGSERVER_OK; // For make_request ().
-
- client_request_get_version req;
-
- /* This indicates that we failed to connect to cygserver at all but
- * that's fine as cygwin doesn't need it to be running.
- */
- if (req.make_request () == -1)
- return false;
-
- /* We connected to the server but something went wrong after that
- * (in sending the message, in cygserver itself, or in receiving the
- * reply).
- */
- if (req.error_code ())
- {
- syscall_printf ("failure in cygserver version request: %d",
- req.error_code ());
- syscall_printf ("process will continue without cygserver support");
- return false;
- }
-
- return req.check_version ();
-}
-
-void
-cygserver_init ()
-{
- if (!allow_daemon)
- {
- syscall_printf ("cygserver use disabled in client");
- cygserver_running = CYGSERVER_UNAVAIL;
- return;
- }
-
- assert (cygserver_running == CYGSERVER_UNKNOWN \
- || cygserver_running == CYGSERVER_OK \
- || cygserver_running == CYGSERVER_UNAVAIL);
-
- if (cygserver_running == CYGSERVER_OK)
- return;
-
- if (!check_cygserver_available ())
- cygserver_running = CYGSERVER_UNAVAIL;
-}
diff --git a/winsup/cygwin/cygserver_process.cc b/winsup/cygwin/cygserver_process.cc
deleted file mode 100755
index 2cc7be19c92..00000000000
--- a/winsup/cygwin/cygserver_process.cc
+++ /dev/null
@@ -1,431 +0,0 @@
-/* cygserver_process.cc
-
- Copyright 2001, 2002 Red Hat Inc.
-
- Written by Robert Collins <rbtcollins@hotmail.com>
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-#include "woutsup.h"
-
-#include <sys/types.h>
-
-#include <assert.h>
-#include <stdlib.h>
-
-#include "cygerrno.h"
-
-#include "cygwin/cygserver_process.h"
-
-/*****************************************************************************/
-
-#define elements(ARRAY) (sizeof (ARRAY) / sizeof (*ARRAY))
-
-/*****************************************************************************/
-
-process_cleanup::~process_cleanup ()
-{
- safe_delete (_process);
-}
-
-void
-process_cleanup::process ()
-{
- _process->cleanup ();
-}
-
-/*****************************************************************************/
-
-/* cleanup_routine */
-cleanup_routine::~cleanup_routine ()
-{
-}
-
-/*****************************************************************************/
-
-process::process (const pid_t cygpid, const DWORD winpid)
- : _cygpid (cygpid),
- _winpid (winpid),
- _hProcess (NULL),
- _cleaning_up (false),
- _exit_status (STILL_ACTIVE),
- _routines_head (NULL),
- _next (NULL)
-{
- _hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, winpid);
- if (!_hProcess)
- {
- system_printf ("unable to obtain handle for new cache process %d(%lu)",
- _cygpid, _winpid);
- _hProcess = INVALID_HANDLE_VALUE;
- _exit_status = 0;
- }
- else
- debug_printf ("got handle %p for new cache process %d(%lu)",
- _hProcess, _cygpid, _winpid);
- InitializeCriticalSection (&_access);
-}
-
-process::~process ()
-{
- DeleteCriticalSection (&_access);
- (void) CloseHandle (_hProcess);
-}
-
-/* No need to be thread-safe as this is only ever called by
- * process_cache::remove_process (). If it has to be made thread-safe
- * later on, it should not use the `access' critical section as that
- * is held by the client request handlers for an arbitrary length of
- * time, i.e. while they do whatever processing is required for a
- * client request.
- */
-DWORD
-process::check_exit_code ()
-{
- if (_hProcess && _hProcess != INVALID_HANDLE_VALUE
- && _exit_status == STILL_ACTIVE
- && !GetExitCodeProcess (_hProcess, &_exit_status))
- {
- system_printf ("failed to retrieve exit code for %d(%lu), error = %lu",
- _cygpid, _winpid, GetLastError ());
- _hProcess = INVALID_HANDLE_VALUE;
- }
- return _exit_status;
-}
-
-bool
-process::add (cleanup_routine *const entry)
-{
- assert (entry);
-
- bool res = false;
- EnterCriticalSection (&_access);
-
- if (!_cleaning_up)
- {
- entry->_next = _routines_head;
- _routines_head = entry;
- res = true;
- }
-
- LeaveCriticalSection (&_access);
- return res;
-}
-
-bool
-process::remove (const cleanup_routine *const entry)
-{
- assert (entry);
-
- bool res = false;
- EnterCriticalSection (&_access);
-
- if (!_cleaning_up)
- {
- cleanup_routine *previous = NULL;
-
- for (cleanup_routine *ptr = _routines_head;
- ptr;
- previous = ptr, ptr = ptr->_next)
- {
- if (*ptr == *entry)
- {
- if (previous)
- previous->_next = ptr->_next;
- else
- _routines_head = ptr->_next;
-
- safe_delete (ptr);
- res = true;
- break;
- }
- }
- }
-
- LeaveCriticalSection (&_access);
- return res;
-}
-
-/* This is single threaded. It's called after the process is removed
- * from the cache, but inserts may be attemped by worker threads that
- * have a pointer to it.
- */
-void
-process::cleanup ()
-{
- EnterCriticalSection (&_access);
- assert (!is_active ());
- assert (!_cleaning_up);
- InterlockedExchange (&_cleaning_up, true);
- cleanup_routine *entry = _routines_head;
- _routines_head = NULL;
- LeaveCriticalSection (&_access);
-
- while (entry)
- {
- cleanup_routine *const ptr = entry;
- entry = entry->_next;
- ptr->cleanup (this);
- safe_delete (ptr);
- }
-}
-
-/*****************************************************************************/
-
-void
-process_cache::submission_loop::request_loop ()
-{
- assert (this);
- assert (_cache);
- assert (_interrupt_event);
-
- while (_running)
- _cache->wait_for_processes (_interrupt_event);
-}
-
-/*****************************************************************************/
-
-process_cache::process_cache (const unsigned int initial_workers)
- : _queue (initial_workers),
- _submitter (this, &_queue), // true == interruptible
- _processes_count (0),
- _processes_head (NULL),
- _cache_add_trigger (NULL)
-{
- /* there can only be one */
- InitializeCriticalSection (&_cache_write_access);
-
- _cache_add_trigger = CreateEvent (NULL, // SECURITY_ATTRIBUTES
- FALSE, // Auto-reset
- FALSE, // Initially non-signalled
- NULL); // Anonymous
-
- if (!_cache_add_trigger)
- {
- system_printf ("failed to create cache add trigger, error = %lu",
- GetLastError ());
- abort ();
- }
-
- _queue.add_submission_loop (&_submitter);
-}
-
-process_cache::~process_cache ()
-{
- (void) CloseHandle (_cache_add_trigger);
- DeleteCriticalSection (&_cache_write_access);
-}
-
-/* This returns the process object to the caller already locked, that
- * is, with the object's `access' critical region entered. Thus the
- * caller must unlock the object when it's finished with it (via
- * process::release ()). It must then not try to access the object
- * afterwards, except by going through this routine again, as it may
- * have been deleted once it has been unlocked.
- */
-class process *
-process_cache::process (const pid_t cygpid, const DWORD winpid)
-{
- /* TODO: make this more granular, so a search doesn't involve the
- * write lock.
- */
- EnterCriticalSection (&_cache_write_access);
- class process *previous = NULL;
- class process *entry = find (winpid, &previous);
-
- if (!entry)
- {
- if (_processes_count + SPECIALS_COUNT >= MAXIMUM_WAIT_OBJECTS)
- {
- LeaveCriticalSection (&_cache_write_access);
- system_printf (("process limit (%d processes) reached; "
- "new connection refused for %d(%lu)"),
- MAXIMUM_WAIT_OBJECTS - SPECIALS_COUNT,
- cygpid, winpid);
- set_errno (EAGAIN);
- return NULL;
- }
-
- entry = safe_new (class process, cygpid, winpid);
- if (!entry->is_active ())
- {
- LeaveCriticalSection (&_cache_write_access);
- safe_delete (entry);
- set_errno (ESRCH);
- return NULL;
- }
-
- if (previous)
- {
- entry->_next = previous->_next;
- previous->_next = entry;
- }
- else
- {
- entry->_next = _processes_head;
- _processes_head = entry;
- }
-
- _processes_count += 1;
- SetEvent (_cache_add_trigger);
- }
-
- EnterCriticalSection (&entry->_access); // To be released by the caller.
- LeaveCriticalSection (&_cache_write_access);
- assert (entry);
- assert (entry->_winpid == winpid);
- return entry;
-}
-
-void
-process_cache::wait_for_processes (const HANDLE interrupt_event)
-{
- // Update `_wait_array' with handles of all current processes.
- const size_t count = sync_wait_array (interrupt_event);
-
- debug_printf ("waiting on %u objects in total (%u processes)",
- count, _processes_count);
-
- const DWORD rc = WaitForMultipleObjects (count, _wait_array,
- FALSE, INFINITE);
-
- if (rc == WAIT_FAILED)
- {
- system_printf ("could not wait on the process handles, error = %lu",
- GetLastError ());
- abort ();
- }
-
- const size_t start = rc - WAIT_OBJECT_0;
-
- if (rc < WAIT_OBJECT_0 || start > count)
- {
- system_printf (("unexpected return code %rc "
- "from WaitForMultipleObjects: "
- "expected [%u .. %u)"),
- rc, WAIT_OBJECT_0, WAIT_OBJECT_0 + count);
- abort ();
- }
-
- // Tell all the processes, from the signalled point up, the bad news.
- for (size_t index = start; index != count; index++)
- if (_process_array[index])
- check_and_remove_process (index);
-}
-
-/*
- * process_cache::sync_wait_array ()
- *
- * Fill-in the wait array with the handles that the cache needs to wait on.
- * These handles are:
- * - the process_process_param's interrupt event
- * - the process_cache's cache_add_trigger event
- * - the handle for each live process in the cache.
- *
- * Return value: the number of live handles in the array.
- */
-
-size_t
-process_cache::sync_wait_array (const HANDLE interrupt_event)
-{
- assert (this);
- assert (_cache_add_trigger && _cache_add_trigger != INVALID_HANDLE_VALUE);
- assert (interrupt_event && interrupt_event != INVALID_HANDLE_VALUE);
-
- EnterCriticalSection (&_cache_write_access);
-
- assert (_processes_count + SPECIALS_COUNT <= elements (_wait_array));
-
- size_t index = 0;
-
- for (class process *ptr = _processes_head; ptr; ptr = ptr->_next)
- {
- assert (ptr->_hProcess && ptr->_hProcess != INVALID_HANDLE_VALUE);
- assert (ptr->is_active ());
-
- _wait_array[index] = ptr->handle ();
- _process_array[index++] = ptr;
-
- assert (index <= elements (_wait_array));
- }
-
- /* Sorry for shouting, but THESE MUST BE ADDED AT THE END! */
- /* Well, not strictly `must', but it's more efficient if they are :-) */
-
- _wait_array[index] = interrupt_event;
- _process_array[index++] = NULL;
-
- _wait_array[index] = _cache_add_trigger;
- _process_array[index++] = NULL;
-
- /* Phew, back to normal volume now. */
-
- assert (index <= elements (_wait_array));
-
- LeaveCriticalSection (&_cache_write_access);
-
- return index;
-}
-
-void
-process_cache::check_and_remove_process (const size_t index)
-{
- assert (this);
- assert (index < elements (_wait_array) - SPECIALS_COUNT);
-
- class process *const process = _process_array[index];
-
- assert (process);
- assert (process->handle () == _wait_array[index]);
-
- if (process->check_exit_code () == STILL_ACTIVE)
- return;
-
- debug_printf ("process %d(%lu) has left the building ($? = %lu)",
- process->_cygpid, process->_winpid, process->_exit_status);
-
- /* Unlink the process object from the process list. */
-
- EnterCriticalSection (&_cache_write_access);
-
- class process *previous = NULL;
-
- const class process *const tmp = find (process->_winpid, &previous);
-
- assert (tmp == process);
- assert (previous ? previous->_next == process : _processes_head == process);
-
- if (previous)
- previous->_next = process->_next;
- else
- _processes_head = process->_next;
-
- _processes_count -= 1;
- LeaveCriticalSection (&_cache_write_access);
-
- /* Schedule any cleanup tasks for this process. */
- _queue.add (safe_new (process_cleanup, process));
-}
-
-class process *
-process_cache::find (const DWORD winpid, class process **previous)
-{
- if (previous)
- *previous = NULL;
-
- for (class process *ptr = _processes_head; ptr; ptr = ptr->_next)
- if (ptr->_winpid == winpid)
- return ptr;
- else if (ptr->_winpid > winpid) // The list is sorted by winpid.
- return NULL;
- else if (previous)
- *previous = ptr;
-
- return NULL;
-}
-
-/*****************************************************************************/
diff --git a/winsup/cygwin/cygserver_shm.h b/winsup/cygwin/cygserver_shm.h
deleted file mode 100644
index 5a5ee38207e..00000000000
--- a/winsup/cygwin/cygserver_shm.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* cygserver_shm.h: Single unix specification IPC interface for Cygwin.
-
- Copyright 2002 Red Hat, Inc.
-
- Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
- Based on code by Robert Collins <robert.collins@hotmail.com>.
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-#ifndef __CYGSERVER_SHM_H__
-#define __CYGSERVER_SHM_H__
-
-#include <sys/types.h>
-#include <cygwin/shm.h>
-
-#include <assert.h>
-#include <limits.h>
-
-#include "cygserver_ipc.h"
-
-#include "cygwin/cygserver.h"
-
-/*---------------------------------------------------------------------------*
- * Values for the shminfo entries.
- *
- * Nb. The values are segregated between two enums so that the `small'
- * values aren't promoted to `unsigned long' equivalents.
- *---------------------------------------------------------------------------*/
-
-enum
- {
- SHMMAX = ULONG_MAX,
- SHMSEG = ULONG_MAX,
- SHMALL = ULONG_MAX
- };
-
-enum
- {
- SHMMIN = 1,
- SHMMNI = IPCMNI // Must be <= IPCMNI.
- };
-
-/*---------------------------------------------------------------------------*
- * class client_request_shm
- *---------------------------------------------------------------------------*/
-
-#ifndef __INSIDE_CYGWIN__
-class transport_layer_base;
-class process_cache;
-#endif
-
-class client_request_shm : public client_request
-{
- friend class client_request;
-
-public:
- enum shmop_t
- {
- SHMOP_shmat,
- SHMOP_shmctl,
- SHMOP_shmdt,
- SHMOP_shmget
- };
-
-#ifdef __INSIDE_CYGWIN__
- client_request_shm (int shmid, int shmflg); // shmat
- client_request_shm (int shmid, int cmd, const struct shmid_ds *); // shmctl
- client_request_shm (int shmid); // shmdt
- client_request_shm (key_t, size_t, int shmflg); // shmget
-#endif
-
- // Accessors for out parameters.
-
- int shmid () const
- {
- assert (!error_code ());
- return _parameters.out.shmid;
- }
-
- HANDLE hFileMap () const
- {
- assert (!error_code ());
- return _parameters.out.hFileMap;
- }
-
- const struct shmid_ds & ds () const
- {
- assert (!error_code ());
- return _parameters.out.ds;
- }
-
- const struct shminfo & shminfo () const
- {
- assert (!error_code ());
- return _parameters.out.shminfo;
- }
-
- const struct shm_info & shm_info () const
- {
- assert (!error_code ());
- return _parameters.out.shm_info;
- }
-
-private:
- union
- {
- struct
- {
- shmop_t shmop;
- key_t key;
- size_t size;
- int shmflg;
- int shmid;
- int cmd;
- pid_t cygpid;
- DWORD winpid;
- __uid32_t uid;
- __gid32_t gid;
- struct shmid_ds ds;
- } in;
-
- struct {
- int shmid;
- union
- {
- HANDLE hFileMap;
- struct shmid_ds ds;
- struct shminfo shminfo;
- struct shm_info shm_info;
- };
- } out;
- } _parameters;
-
-#ifndef __INSIDE_CYGWIN__
- client_request_shm ();
-#endif
-
-#ifndef __INSIDE_CYGWIN__
- virtual void serve (transport_layer_base *, process_cache *);
-#endif
-};
-
-#endif /* __CYGSERVER_SHM_H__ */
diff --git a/winsup/cygwin/cygserver_transport_pipes.cc b/winsup/cygwin/cygserver_transport_pipes.cc
deleted file mode 100755
index 6d80defd4ed..00000000000
--- a/winsup/cygwin/cygserver_transport_pipes.cc
+++ /dev/null
@@ -1,362 +0,0 @@
-/* cygserver_transport_pipes.cc
-
- Copyright 2001, 2002 Red Hat Inc.
-
- Written by Robert Collins <rbtcollins@hotmail.com>
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-/* to allow this to link into cygwin and the .dll, a little magic is needed. */
-#ifdef __OUTSIDE_CYGWIN__
-#include "woutsup.h"
-#else
-#include "winsup.h"
-#endif
-
-#include <sys/types.h>
-
-#include <assert.h>
-#include <netdb.h>
-#include <pthread.h>
-#include <unistd.h>
-
-#include "cygerrno.h"
-#include "cygwin/cygserver_transport.h"
-#include "cygwin/cygserver_transport_pipes.h"
-
-#ifndef __INSIDE_CYGWIN__
-#include "cygwin/cygserver.h"
-#endif
-
-enum
- {
- MAX_WAIT_NAMED_PIPE_RETRY = 64,
- WAIT_NAMED_PIPE_TIMEOUT = 10 // milliseconds
- };
-
-#ifndef __INSIDE_CYGWIN__
-
-static pthread_once_t pipe_instance_lock_once = PTHREAD_ONCE_INIT;
-static CRITICAL_SECTION pipe_instance_lock;
-static long pipe_instance = 0;
-
-static void
-initialise_pipe_instance_lock ()
-{
- assert (pipe_instance == 0);
- InitializeCriticalSection (&pipe_instance_lock);
-}
-
-#endif /* !__INSIDE_CYGWIN__ */
-
-#ifndef __INSIDE_CYGWIN__
-
-transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe)
- : _pipe_name (""),
- _hPipe (hPipe),
- _is_accepted_endpoint (true),
- _is_listening_endpoint (false)
-{
- assert (_hPipe);
- assert (_hPipe != INVALID_HANDLE_VALUE);
-
- init_security ();
-}
-
-#endif /* !__INSIDE_CYGWIN__ */
-
-transport_layer_pipes::transport_layer_pipes ()
- : _pipe_name ("\\\\.\\pipe\\cygwin_lpc"),
- _hPipe (NULL),
- _is_accepted_endpoint (false),
- _is_listening_endpoint (false)
-{
- init_security ();
-}
-
-void
-transport_layer_pipes::init_security ()
-{
- assert (wincap.has_security ());
-
- /* FIXME: pthread_once or equivalent needed */
-
- InitializeSecurityDescriptor (&_sd, SECURITY_DESCRIPTOR_REVISION);
- SetSecurityDescriptorDacl (&_sd, TRUE, NULL, FALSE);
-
- _sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES);
- _sec_all_nih.lpSecurityDescriptor = &_sd;
- _sec_all_nih.bInheritHandle = FALSE;
-}
-
-transport_layer_pipes::~transport_layer_pipes ()
-{
- close ();
-}
-
-#ifndef __INSIDE_CYGWIN__
-
-int
-transport_layer_pipes::listen ()
-{
- assert (!_hPipe);
- assert (!_is_accepted_endpoint);
- assert (!_is_listening_endpoint);
-
- _is_listening_endpoint = true;
-
- /* no-op */
- return 0;
-}
-
-class transport_layer_pipes *
-transport_layer_pipes::accept (bool *const recoverable)
-{
- assert (!_hPipe);
- assert (!_is_accepted_endpoint);
- assert (_is_listening_endpoint);
-
- pthread_once (&pipe_instance_lock_once, &initialise_pipe_instance_lock);
-
- EnterCriticalSection (&pipe_instance_lock);
-
- // Read: http://www.securityinternals.com/research/papers/namedpipe.php
- // See also the Microsoft security bulletins MS00-053 and MS01-031.
-
- // FIXME: Remove FILE_CREATE_PIPE_INSTANCE.
-
- const bool first_instance = (pipe_instance == 0);
-
- const HANDLE accept_pipe =
- CreateNamedPipe (_pipe_name,
- (PIPE_ACCESS_DUPLEX
- | (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0)),
- (PIPE_TYPE_BYTE | PIPE_WAIT),
- PIPE_UNLIMITED_INSTANCES,
- 0, 0, 1000,
- &_sec_all_nih);
-
- const bool duplicate = (accept_pipe == INVALID_HANDLE_VALUE
- && pipe_instance == 0
- && GetLastError () == ERROR_ACCESS_DENIED);
-
- if (accept_pipe != INVALID_HANDLE_VALUE)
- InterlockedIncrement (&pipe_instance);
-
- LeaveCriticalSection (&pipe_instance_lock);
-
- if (duplicate)
- {
- *recoverable = false;
- system_printf ("failed to create named pipe: "
- "is the daemon already running?");
- return NULL;
- }
-
- if (accept_pipe == INVALID_HANDLE_VALUE)
- {
- debug_printf ("error creating pipe (%lu).", GetLastError ());
- *recoverable = true; // FIXME: case analysis?
- return NULL;
- }
-
- assert (accept_pipe);
-
- if (!ConnectNamedPipe (accept_pipe, NULL)
- && GetLastError () != ERROR_PIPE_CONNECTED)
- {
- debug_printf ("error connecting to pipe (%lu)", GetLastError ());
- (void) CloseHandle (accept_pipe);
- *recoverable = true; // FIXME: case analysis?
- return NULL;
- }
-
- return safe_new (transport_layer_pipes, accept_pipe);
-}
-
-#endif /* !__INSIDE_CYGWIN__ */
-
-void
-transport_layer_pipes::close ()
-{
- // verbose: debug_printf ("closing pipe %p", _hPipe);
-
- if (_hPipe)
- {
- assert (_hPipe != INVALID_HANDLE_VALUE);
-
-#ifndef __INSIDE_CYGWIN__
-
- if (_is_accepted_endpoint)
- {
- (void) FlushFileBuffers (_hPipe); // Blocks until client reads.
- (void) DisconnectNamedPipe (_hPipe);
- EnterCriticalSection (&pipe_instance_lock);
- (void) CloseHandle (_hPipe);
- assert (pipe_instance > 0);
- InterlockedDecrement (&pipe_instance);
- LeaveCriticalSection (&pipe_instance_lock);
- }
- else
- (void) CloseHandle (_hPipe);
-
-#else /* __INSIDE_CYGWIN__ */
-
- assert (!_is_accepted_endpoint);
- (void) ForceCloseHandle (_hPipe);
-
-#endif /* __INSIDE_CYGWIN__ */
-
- _hPipe = NULL;
- }
-}
-
-ssize_t
-transport_layer_pipes::read (void *const buf, const size_t len)
-{
- // verbose: debug_printf ("reading from pipe %p", _hPipe);
-
- assert (_hPipe);
- assert (_hPipe != INVALID_HANDLE_VALUE);
- assert (!_is_listening_endpoint);
-
- DWORD count;
- if (!ReadFile (_hPipe, buf, len, &count, NULL))
- {
- debug_printf ("error reading from pipe (%lu)", GetLastError ());
- set_errno (EINVAL); // FIXME?
- return -1;
- }
-
- return count;
-}
-
-ssize_t
-transport_layer_pipes::write (void *const buf, const size_t len)
-{
- // verbose: debug_printf ("writing to pipe %p", _hPipe);
-
- assert (_hPipe);
- assert (_hPipe != INVALID_HANDLE_VALUE);
- assert (!_is_listening_endpoint);
-
- DWORD count;
- if (!WriteFile (_hPipe, buf, len, &count, NULL))
- {
- debug_printf ("error writing to pipe, error = %lu", GetLastError ());
- set_errno (EINVAL); // FIXME?
- return -1;
- }
-
- return count;
-}
-
-/*
- * This routine holds a static variable, assume_cygserver, that is set
- * if the transport has good reason to think that cygserver is
- * running, i.e. if if successfully connected to it with the previous
- * attempt. If this is set, the code tries a lot harder to get a
- * connection, making the assumption that any failures are just
- * congestion and overloading problems.
- */
-
-int
-transport_layer_pipes::connect ()
-{
- assert (!_hPipe);
- assert (!_is_accepted_endpoint);
- assert (!_is_listening_endpoint);
-
- static bool assume_cygserver = false;
-
- BOOL rc = TRUE;
- int retries = 0;
-
- while (rc)
- {
- _hPipe = CreateFile (_pipe_name,
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- &_sec_all_nih,
- OPEN_EXISTING,
- SECURITY_IMPERSONATION,
- NULL);
-
- if (_hPipe != INVALID_HANDLE_VALUE)
- {
- assert (_hPipe);
-#ifdef __INSIDE_CYGWIN__
- ProtectHandle (_hPipe);
-#endif
- assume_cygserver = true;
- return 0;
- }
-
- _hPipe = NULL;
-
- if (!assume_cygserver && GetLastError () != ERROR_PIPE_BUSY)
- {
- debug_printf ("Error opening the pipe (%lu)", GetLastError ());
- return -1;
- }
-
- /* Note: `If no instances of the specified named pipe exist, the
- * WaitNamedPipe function returns immediately, regardless of the
- * time-out value.' Thus the explicit Sleep if the call fails
- * with ERROR_FILE_NOT_FOUND.
- */
- while (retries != MAX_WAIT_NAMED_PIPE_RETRY
- && !(rc = WaitNamedPipe (_pipe_name, WAIT_NAMED_PIPE_TIMEOUT)))
- {
- if (GetLastError () == ERROR_FILE_NOT_FOUND)
- Sleep (0); // Give the server a chance.
-
- retries += 1;
- }
- }
-
- assert (retries == MAX_WAIT_NAMED_PIPE_RETRY);
-
- system_printf ("lost connection to cygserver, error = %lu",
- GetLastError ());
-
- assume_cygserver = false;
-
- return -1;
-}
-
-#ifndef __INSIDE_CYGWIN__
-
-void
-transport_layer_pipes::impersonate_client ()
-{
- assert (_hPipe);
- assert (_hPipe != INVALID_HANDLE_VALUE);
- assert (_is_accepted_endpoint);
-
- // verbose: debug_printf ("impersonating pipe %p", _hPipe);
- if (_hPipe)
- {
- assert (_hPipe != INVALID_HANDLE_VALUE);
-
- if (!ImpersonateNamedPipeClient (_hPipe))
- debug_printf ("Failed to Impersonate the client, (%lu)",
- GetLastError ());
- }
- // verbose: debug_printf ("I am who you are");
-}
-
-void
-transport_layer_pipes::revert_to_self ()
-{
- assert (_is_accepted_endpoint);
-
- RevertToSelf ();
- // verbose: debug_printf ("I am who I yam");
-}
-
-#endif /* !__INSIDE_CYGWIN__ */
diff --git a/winsup/cygwin/cygthread.h b/winsup/cygwin/cygthread.h
index 57b50e20af3..b8566d4c7e0 100644
--- a/winsup/cygwin/cygthread.h
+++ b/winsup/cygwin/cygthread.h
@@ -18,12 +18,12 @@ class cygthread
LPTHREAD_START_ROUTINE func;
VOID *arg;
bool is_freerange;
- static DWORD main_thread_id;
static bool exiting;
static DWORD WINAPI stub (VOID *);
static DWORD WINAPI simplestub (VOID *);
void terminate_thread ();
public:
+ static DWORD main_thread_id;
static const char * name (DWORD = 0);
cygthread (LPTHREAD_START_ROUTINE, LPVOID, const char *);
cygthread () {};
diff --git a/winsup/cygwin/dlmalloc.c b/winsup/cygwin/dlmalloc.c
new file mode 100644
index 00000000000..1fb349221a3
--- /dev/null
+++ b/winsup/cygwin/dlmalloc.c
@@ -0,0 +1,3894 @@
+/*
+ * To do:
+ * - strdup? maybe shouldn't bother yet, it seems difficult to get includes
+ * right using dlmalloc.h
+ * - add STD_C prototyping
+ * - adhere to comment conventions
+ * - maybe fix ALLOCFILL vs. MOATFILL in do_init_realloced_chunk()
+ * - keep a list of mmaped regions for checking in malloc_update_mallinfo()
+ * - I think memalign() is wrong: it aligns the chunk rather than the memory
+ * portion of the chunk.
+ * - "& -alignment" in memalign() is suspect: should use "& ~alignment"
+ * instead?
+ * - malloc.h doesn't need malloc_COPY or probably a bunch of other stuff
+ * - add mallopt options for e.g. fill?
+ * - come up with a non-BBC version of M_C
+ * - document necessity of checking chunk address in do_check_chunk prior to
+ * accessing any of its fields
+ * Done:
+ * minor speedup due to extend check before mremap
+ * minor speedup due to returning malloc() result in memalign() if aligned
+ * made malloc_update_mallinfo() check alloced regions at start of sbrk area
+ * fixed bug: After discovering foreign sbrk, if old_top was MINSIZE, would
+ * reduce old_top_size to 0, thus making inuse(old_top) return 0; other
+ * functions would consequently attempt to access old_top->{fd,bk}, which
+ * were invalid. This is in malloc_extend_top(), in the "double
+ * fencepost" section.
+ * Documentation:
+ * malloc_usable_size(P) is equivalent to realloc(P, malloc_usable_size(P))
+ *
+ * $Log$
+ * Revision 1.5.52.1 2003/09/02 02:31:08 cgf
+ * merge from trunk
+ *
+ * Revision 1.6 2003/08/31 18:26:58 cgf
+ * * Makefile.in (MALLOC_OFILES): Always fill in with correct malloc object.
+ * * configure.in: Fill in MALLOC_OFILES with either debugging or regular malloc.
+ * * configure: Regenerate.
+ * * dlmalloc.c: Make various fruitless changes to attempt to get to work.
+ * * dlmalloc.h: Ditto.
+ * * malloc.cc (free): Check malloc pool when debugging.
+ * * path.cc (win32_device_name): Eliminate compiler warning.
+ * * sigproc.cc (sig_dispatch_pending): Remove use of was_pending. Let
+ * thisframe.call_signal_handler decide if handler should be called rather than
+ * using bogus was_pending check.
+ * * exceptions.cc (interrupt_setup): Remove accidentally checked in debugging
+ * code.
+ * * heap.cc (sbrk): Save rounded addess in user_heap_max.
+ *
+ * Revision 1.5 2001/10/03 03:49:25 cgf
+ * * cygheap.cc (cfree): Remove malloc debugging probe.
+ * * dlmalloc.c (errprint): Remove abort() call which causes interesting error
+ * message printing to abort prematurely.
+ * * environ.cc: Sprinkle MALLOC_CHECKs liberally throughout.
+ * (_addenv): Allocate two empty elements at end of environ to
+ * (apparently) work around problems with some buggy applications.
+ * (winenv): Avoid calling alloca if no forced environment variable is present.
+ *
+ * * exceptions.cc (open_stackdumpfile): Don't print "Dumping stack trace to..."
+ * when running in a cygwin environment (i.e., the parent is a cygwin process).
+ *
+ * * dtable.cc (dtable::init_std_file_from_handle): Move device type detection
+ * code from build_fhandler here since it is only used by this function.
+ * (dtable::build_fhandler_from_name): New method. Renamed from
+ * dtable::build_fhandler.
+ * (dtable::build_fhandler): Use build_fhandler_from_name.
+ * (cygwin_attach_handle_to_fd): Ditto.
+ * * syscalls.cc (_open): Ditto.
+ * (stat_worker): Ditto.
+ * * dtable.h (dtable::build_fhandler_from_name): Rename declaration from
+ * dtable::build_fhandler.
+ *
+ * Revision 1.4 2001/09/07 21:32:04 cgf
+ * * cygheap.h (init_cygheap): Move heap pointers here.
+ * * include/sys/cygwin.h (perprocess): Remove heap pointers.
+ * * dcrt0.cc (__cygwin_user_data): Reflect obsolete perprocess stuff.
+ * (_dll_crt0): Don't initialize heap pointers.
+ * (cygwin_dll_init): Ditto.
+ * (release_upto): Use heap pointers from cygheap.
+ * * heap.h: Ditto.
+ * * fork.cc (fork_parent): Ditto. Don't set heap pointers in ch.
+ * (fork_child): Remove obsolete sigproc_fixup_after_fork.
+ * * shared.cc (memory_init): Reorganize so that cygheap initialization is called
+ * prior to regular heap since regular heap uses cygheap now.
+ * * sigproc.cc (proc_subproc): Eliminate zombies allocation.
+ * (sigproc_init): Move zombies alloation here. Don't free up array on fork, just
+ * reuse it.
+ * (sigproc_fixup_after_fork): Eliminate.
+ * * sigproc.h: Ditto.
+ * * include/cygwin/version.h: Reflect change to perprocess structure.
+ *
+ * Revision 1.3 2001/06/26 14:47:48 cgf
+ * * mmap.cc: Clean up *ResourceLock calls throughout.
+ * * thread.cc (pthread_cond::TimedWait): Check for WAIT_TIMEOUT as well as
+ * WAIT_ABANDONED.
+ * (__pthread_cond_timedwait): Calculate a relative wait from the abstime
+ * parameter.
+ *
+ * Revision 1.2 2001/06/24 22:26:49 cgf
+ * forced commit
+ *
+ * Revision 1.1 2001/04/24 15:25:30 duda
+ * * dlmalloc.c: New file. Port of Doug Lea's malloc
+ * * dlmalloc.h: Ditto.
+ * * Makefile.in: Add support for MALLOC_DEBUG
+ * * config.h.in: Ditto.
+ * * winsup.h: Ditto.
+ * * configure.in: Add --enable-malloc-debugging option.
+ * * configure: Regenerate.
+ * * debug.h: Include declarations for debugging malloc.
+ * * tty.cc (grantpt): Fix definition.
+ * (unlockpt): Ditto.
+ *
+ * Revision 1.1 1997/12/24 18:34:47 nsd
+ * Initial revision
+ *
+ */
+/* ---------- To make a malloc.h, start cutting here ------------ */
+
+/*
+ A version of malloc/free/realloc written by Doug Lea and released to the
+ public domain. Send questions/comments/complaints/performance data
+ to dl@cs.oswego.edu
+
+* VERSION 2.6.4 Thu Nov 28 07:54:55 1996 Doug Lea (dl at gee)
+
+ Note: There may be an updated version of this malloc obtainable at
+ ftp://g.oswego.edu/pub/misc/malloc.c
+ Check before installing!
+
+* Why use this malloc?
+
+ This is not the fastest, most space-conserving, most portable, or
+ most tunable malloc ever written. However it is among the fastest
+ while also being among the most space-conserving, portable and tunable.
+ Consistent balance across these factors results in a good general-purpose
+ allocator. For a high-level description, see
+ http://g.oswego.edu/dl/html/malloc.html
+
+* Synopsis of public routines
+
+ (Much fuller descriptions are contained in the program documentation below.)
+
+ malloc(size_t n);
+ Return a pointer to a newly allocated chunk of at least n bytes, or null
+ if no space is available.
+ free(Void_t* p);
+ Release the chunk of memory pointed to by p, or no effect if p is null.
+ realloc(Void_t* p, size_t n);
+ Return a pointer to a chunk of size n that contains the same data
+ as does chunk p up to the minimum of (n, p's size) bytes, or null
+ if no space is available. The returned pointer may or may not be
+ the same as p. If p is null, equivalent to malloc. Unless the
+ #define realloc_ZERO_BYTES_FREES below is set, realloc with a
+ size argument of zero (re)allocates a minimum-sized chunk.
+ memalign(size_t alignment, size_t n);
+ Return a pointer to a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument, which must be a power of
+ two.
+ valloc(size_t n);
+ Equivalent to memalign(pagesize, n), where pagesize is the page
+ size of the system (or as near to this as can be figured out from
+ all the includes/defines below.)
+ pvalloc(size_t n);
+ Equivalent to valloc(minimum-page-that-holds(n)), that is,
+ round up n to nearest pagesize.
+ calloc(size_t unit, size_t quantity);
+ Returns a pointer to quantity * unit bytes, with all locations
+ set to zero.
+ cfree(Void_t* p);
+ Equivalent to free(p).
+ malloc_trim(size_t pad);
+ Release all but pad bytes of freed top-most memory back
+ to the system. Return 1 if successful, else 0.
+ malloc_usable_size(Void_t* p);
+ Report the number usable allocated bytes associated with allocated
+ chunk p. This may or may not report more bytes than were requested,
+ due to alignment and minimum size constraints.
+ malloc_stats();
+ Prints brief summary statistics on stderr.
+ mallinfo()
+ Returns (by copy) a struct containing various summary statistics.
+ mallopt(int parameter_number, int parameter_value)
+ Changes one of the tunable parameters described below. Returns
+ 1 if successful in changing the parameter, else 0.
+
+* Vital statistics:
+
+ Alignment: 8-byte
+ 8 byte alignment is currently hardwired into the design. This
+ seems to suffice for all current machines and C compilers.
+
+ Assumed pointer representation: 4 or 8 bytes
+ Code for 8-byte pointers is untested by me but has worked
+ reliably by Wolfram Gloger, who contributed most of the
+ changes supporting this.
+
+ Assumed size_t representation: 4 or 8 bytes
+ Note that size_t is allowed to be 4 bytes even if pointers are 8.
+
+ Minimum overhead per allocated chunk: 4 or 8 bytes
+ Each malloced chunk has a hidden overhead of 4 bytes holding size
+ and status information.
+
+ Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead)
+ 8-byte ptrs: 24/32 bytes (including, 4/8 overhead)
+
+ When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+ ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+ needed; 4 (8) for a trailing size field
+ and 8 (16) bytes for free list pointers. Thus, the minimum
+ allocatable size is 16/24/32 bytes.
+
+ Even a request for zero bytes (i.e., malloc(0)) returns a
+ pointer to something of the minimum allocatable size.
+
+ Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes
+ 8-byte size_t: 2^63 - 16 bytes
+
+ It is assumed that (possibly signed) size_t bit values suffice to
+ represent chunk sizes. `Possibly signed' is due to the fact
+ that `size_t' may be defined on a system as either a signed or
+ an unsigned type. To be conservative, values that would appear
+ as negative numbers are avoided.
+ Requests for sizes with a negative sign bit will return a
+ minimum-sized chunk.
+
+ Maximum overhead wastage per allocated chunk: normally 15 bytes
+
+ Alignnment demands, plus the minimum allocatable size restriction
+ make the normal worst-case wastage 15 bytes (i.e., up to 15
+ more bytes will be allocated than were requested in malloc), with
+ two exceptions:
+ 1. Because requests for zero bytes allocate non-zero space,
+ the worst case wastage for a request of zero bytes is 24 bytes.
+ 2. For requests >= mmap_threshold that are serviced via
+ mmap(), the worst case wastage is 8 bytes plus the remainder
+ from a system page (the minimal mmap unit); typically 4096 bytes.
+
+* Limitations
+
+ Here are some features that are NOT currently supported
+
+ * No user-definable hooks for callbacks and the like.
+ * No automated mechanism for fully checking that all accesses
+ to malloced memory stay within their bounds.
+ * No support for compaction.
+
+* Synopsis of compile-time options:
+
+ People have reported using previous versions of this malloc on all
+ versions of Unix, sometimes by tweaking some of the defines
+ below. It has been tested most extensively on Solaris and
+ Linux. It is also reported to work on WIN32 platforms.
+ People have also reported adapting this malloc for use in
+ stand-alone embedded systems.
+
+ The implementation is in straight, hand-tuned ANSI C. Among other
+ consequences, it uses a lot of macros. Because of this, to be at
+ all usable, this code should be compiled using an optimizing compiler
+ (for example gcc -O2) that can simplify expressions and control
+ paths.
+
+ __STD_C (default: derived from C compiler defines)
+ Nonzero if using ANSI-standard C compiler, a C++ compiler, or
+ a C compiler sufficiently close to ANSI to get away with it.
+ DEBUG (default: NOT defined)
+ Define to enable debugging. Adds fairly extensive assertion-based
+ checking to help track down memory errors, but noticeably slows down
+ execution.
+ realloc_ZERO_BYTES_FREES (default: NOT defined)
+ Define this if you think that realloc(p, 0) should be equivalent
+ to free(p). Otherwise, since malloc returns a unique pointer for
+ malloc(0), so does realloc(p, 0).
+ HAVE_memcpy (default: defined)
+ Define if you are not otherwise using ANSI STD C, but still
+ have memcpy and memset in your C library and want to use them.
+ Otherwise, simple internal versions are supplied.
+ USE_memcpy (default: 1 if HAVE_memcpy is defined, 0 otherwise)
+ Define as 1 if you want the C library versions of memset and
+ memcpy called in realloc and calloc (otherwise macro versions are used).
+ At least on some platforms, the simple macro versions usually
+ outperform libc versions.
+ HAVE_MMAP (default: defined as 1)
+ Define to non-zero to optionally make malloc() use mmap() to
+ allocate very large blocks.
+ HAVE_MREMAP (default: defined as 0 unless Linux libc set)
+ Define to non-zero to optionally make realloc() use mremap() to
+ reallocate very large blocks.
+ malloc_getpagesize (default: derived from system #includes)
+ Either a constant or routine call returning the system page size.
+ HAVE_USR_INCLUDE_malloc_H (default: NOT defined)
+ Optionally define if you are on a system with a /usr/include/malloc.h
+ that declares struct mallinfo. It is not at all necessary to
+ define this even if you do, but will ensure consistency.
+ INTERNAL_SIZE_T (default: size_t)
+ Define to a 32-bit type (probably `unsigned int') if you are on a
+ 64-bit machine, yet do not want or need to allow malloc requests of
+ greater than 2^31 to be handled. This saves space, especially for
+ very small chunks.
+ INTERNAL_LINUX_C_LIB (default: NOT defined)
+ Defined only when compiled as part of Linux libc.
+ Also note that there is some odd internal name-mangling via defines
+ (for example, internally, `malloc' is named `mALLOc') needed
+ when compiling in this case. These look funny but don't otherwise
+ affect anything.
+ WIN32 (default: undefined)
+ Define this on MS win (95, nt) platforms to compile in sbrk emulation.
+ LACKS_UNISTD_H (default: undefined)
+ Define this if your system does not have a <unistd.h>.
+ MORECORE (default: sbrk)
+ The name of the routine to call to obtain more memory from the system.
+ MORECORE_FAILURE (default: -1)
+ The value returned upon failure of MORECORE.
+ MORECORE_CLEARS (default 0)
+ True (1) if the routine mapped to MORECORE zeroes out memory (which
+ holds for sbrk).
+ DEFAULT_TRIM_THRESHOLD
+ DEFAULT_TOP_PAD
+ DEFAULT_MMAP_THRESHOLD
+ DEFAULT_MMAP_MAX
+ Default values of tunable parameters (described in detail below)
+ controlling interaction with host system routines (sbrk, mmap, etc).
+ These values may also be changed dynamically via mallopt(). The
+ preset defaults are those that give best performance for typical
+ programs/systems.
+
+
+*/
+
+
+
+
+/* Preliminaries */
+
+#include "winsup.h"
+
+#ifndef __STD_C
+#ifdef __STDC__
+#define __STD_C 1
+#else
+#if __cplusplus
+#define __STD_C 1
+#else
+#define __STD_C 0
+#endif /*__cplusplus*/
+#endif /*__STDC__*/
+#endif /*__STD_C*/
+
+#ifndef Void_t
+#if __STD_C
+#define Void_t void
+#else
+#define Void_t char
+#endif
+#endif /*Void_t*/
+
+#define __MALLOC_H_INCLUDED
+
+#if __STD_C
+#include <stddef.h> /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h> /* needed for malloc_stats */
+
+
+/*
+ Compile-time options
+*/
+
+
+/*
+ Debugging:
+
+ Because freed chunks may be overwritten with link fields, this
+ malloc will often die when freed memory is overwritten by user
+ programs. This can be very effective (albeit in an annoying way)
+ in helping track down dangling pointers.
+
+ If you compile with -DDEBUG, a number of assertion checks are
+ enabled that will catch more memory errors. You probably won't be
+ able to make much sense of the actual assertion errors, but they
+ should help you locate incorrectly overwritten memory. The
+ checking is fairly extensive, and will slow down execution
+ noticeably. Calling malloc_stats or mallinfo with DEBUG set will
+ attempt to check every non-mmapped allocated and free chunk in the
+ course of computing the summmaries. (By nature, mmapped regions
+ cannot be checked very much automatically.)
+
+ Setting DEBUG may also be helpful if you are trying to modify
+ this code. The assertions in the check routines spell out in more
+ detail the assumptions and invariants underlying the algorithms.
+
+*/
+
+#ifdef MALLOC_DEBUG
+#define DEBUG 1
+#define DEBUG1 1
+#define DEBUG2 1
+#define DEBUG3 1
+#endif
+
+#if DEBUG
+#include <assert.h>
+#else
+#define assert(x) ((void)0)
+#endif
+
+/*
+ INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+ of chunk sizes. On a 64-bit machine, you can reduce malloc
+ overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int'
+ at the expense of not being able to handle requests greater than
+ 2^31. This limitation is hardly ever a concern; you are encouraged
+ to set this. However, the default version is the same as size_t.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/*
+ realloc_ZERO_BYTES_FREES should be set if a call to
+ realloc with zero bytes should be the same as a call to free.
+ Some people think it should. Otherwise, since this malloc
+ returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+
+/* #define realloc_ZERO_BYTES_FREES */
+
+
+/*
+ WIN32 causes an emulation of sbrk to be compiled in
+ mmap-based options are not currently supported in WIN32.
+*/
+
+/* #define WIN32 */
+#ifdef WIN32
+#define MORECORE wsbrk
+#define HAVE_MMAP 0
+#endif
+
+
+/*
+ HAVE_memcpy should be defined if you are not otherwise using
+ ANSI STD C, but still have memcpy and memset in your C library
+ and want to use them in calloc and realloc. Otherwise simple
+ macro versions are defined here.
+
+ USE_memcpy should be defined as 1 if you actually want to
+ have memset and memcpy called. People report that the macro
+ versions are often enough faster than libc versions on many
+ systems that it is better to use them.
+
+*/
+
+#define HAVE_memcpy
+
+#ifndef USE_memcpy
+#ifdef HAVE_memcpy
+#define USE_memcpy 1
+#else
+#define USE_memcpy 0
+#endif
+#endif
+
+#if (__STD_C || defined(HAVE_memcpy))
+
+#if __STD_C
+void* memset(void*, int, size_t);
+void* memcpy(void*, const void*, size_t);
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+
+#ifndef DEBUG3
+
+#if USE_memcpy
+
+/* The following macros are only invoked with (2n+1)-multiples of
+ INTERNAL_SIZE_T units, with a positive integer n. This is exploited
+ for fast inline execution when n is small. */
+
+#define malloc_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T mzsz = (nbytes); \
+ if(mzsz <= 9*sizeof(mzsz)) { \
+ INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \
+ if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; \
+ if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; \
+ if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; }}} \
+ *mz++ = 0; \
+ *mz++ = 0; \
+ *mz = 0; \
+ } else memset((charp), 0, mzsz); \
+} while(0)
+
+#define malloc_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T mcsz = (nbytes); \
+ if(mcsz <= 9*sizeof(mcsz)) { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \
+ if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; }}} \
+ *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ *mcdst = *mcsrc ; \
+ } else memcpy(dest, src, mcsz); \
+} while(0)
+
+#else /* !USE_memcpy */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define malloc_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \
+ long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mzp++ = 0; \
+ case 7: *mzp++ = 0; \
+ case 6: *mzp++ = 0; \
+ case 5: *mzp++ = 0; \
+ case 4: *mzp++ = 0; \
+ case 3: *mzp++ = 0; \
+ case 2: *mzp++ = 0; \
+ case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#define malloc_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \
+ long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mcdst++ = *mcsrc++; \
+ case 7: *mcdst++ = *mcsrc++; \
+ case 6: *mcdst++ = *mcsrc++; \
+ case 5: *mcdst++ = *mcsrc++; \
+ case 4: *mcdst++ = *mcsrc++; \
+ case 3: *mcdst++ = *mcsrc++; \
+ case 2: *mcdst++ = *mcsrc++; \
+ case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#endif
+
+#else /* DEBUG3 */
+
+/* The trailing moat invalidates the above prediction about the nbytes
+ parameter to malloc_ZERO and malloc_COPY. */
+
+#define malloc_ZERO(charp, nbytes) \
+do { \
+ char *mzp = (char *)(charp); \
+ long mzn = (nbytes); \
+ while (mzn--) \
+ *mzp++ = '\0'; \
+} while(0)
+
+#define malloc_COPY(dest,src,nbytes) \
+do { \
+ char *mcsrc = (char *)(src); \
+ char *mcdst = (char *)(dest); \
+ long mcn = (nbytes); \
+ while (mcn--) \
+ *mcdst++ = *mcsrc++; \
+} while(0)
+
+#endif /* DEBUG3 */
+
+/*
+ Define HAVE_MMAP to optionally make malloc() use mmap() to
+ allocate very large blocks. These will be returned to the
+ operating system immediately after a free().
+*/
+
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif
+
+/*
+ Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+ large blocks. This is currently only possible on Linux with
+ kernel versions newer than 1.3.77.
+*/
+
+#ifndef HAVE_MREMAP
+#ifdef INTERNAL_LINUX_C_LIB
+#define HAVE_MREMAP 1
+#else
+#define HAVE_MREMAP 0
+#endif
+#endif
+
+#if HAVE_MMAP
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#endif /* HAVE_MMAP */
+
+/*
+ Access to system page size. To the extent possible, this malloc
+ manages memory from the system in page-size units.
+
+ The following mechanics for getpagesize were adapted from
+ bsd/gnu getpagesize.h
+*/
+
+#ifndef LACKS_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifndef malloc_getpagesize
+# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
+# ifndef _SC_PAGE_SIZE
+# define _SC_PAGE_SIZE _SC_PAGESIZE
+# endif
+# endif
+# ifdef _SC_PAGE_SIZE
+# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+# else
+# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+# if __STD_C
+ extern size_t getpagesize(void);
+# else
+ extern size_t getpagesize();
+# endif
+# define malloc_getpagesize getpagesize()
+# else
+# include <sys/param.h>
+# ifdef EXEC_PAGESIZE
+# define malloc_getpagesize EXEC_PAGESIZE
+# else
+# ifdef NBPG
+# ifndef CLSIZE
+# define malloc_getpagesize NBPG
+# else
+# define malloc_getpagesize (NBPG * CLSIZE)
+# endif
+# else
+# ifdef NBPC
+# define malloc_getpagesize NBPC
+# else
+# ifdef PAGESIZE
+# define malloc_getpagesize PAGESIZE
+# else
+# define malloc_getpagesize (4096) /* just guess */
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+
+
+
+/*
+
+ This version of malloc supports the standard SVID/XPG mallinfo
+ routine that returns a struct containing the same kind of
+ information you can get from malloc_stats. It should work on
+ any SVID/XPG compliant system that has a /usr/include/malloc.h
+ defining struct mallinfo. (If you'd like to install such a thing
+ yourself, cut out the preliminary declarations as described above
+ and below and save them in a malloc.h file. But there's no
+ compelling reason to bother to do this.)
+
+ The main declaration needed is the mallinfo struct that is returned
+ (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a
+ bunch of fields, most of which are not even meaningful in this
+ version of malloc. Some of these fields are are instead filled by
+ mallinfo() with other numbers that might possibly be of interest.
+
+ HAVE_USR_INCLUDE_malloc_H should be set if you have a
+ /usr/include/malloc.h file that includes a declaration of struct
+ mallinfo. If so, it is included; else an SVID2/XPG2 compliant
+ version is declared below. These must be precisely the same for
+ mallinfo() to work.
+
+*/
+
+/* #define HAVE_USR_INCLUDE_malloc_H */
+
+#if HAVE_USR_INCLUDE_malloc_H
+#include "/usr/include/malloc.h"
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+ int arena; /* total space allocated from system */
+ int ordblks; /* number of non-inuse chunks */
+ int smblks; /* unused -- always zero */
+ int hblks; /* number of mmapped regions */
+ int hblkhd; /* total space in mmapped regions */
+ int usmblks; /* unused -- always zero */
+ int fsmblks; /* unused -- always zero */
+ int uordblks; /* total allocated space */
+ int fordblks; /* total non-inuse space */
+ int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/* SVID2/XPG mallopt options */
+
+#define M_MXFAST 1 /* UNUSED in this malloc */
+#define M_NLBLKS 2 /* UNUSED in this malloc */
+#define M_GRAIN 3 /* UNUSED in this malloc */
+#define M_KEEP 4 /* UNUSED in this malloc */
+
+#endif
+
+/* mallopt options that actually do something */
+
+#define M_TRIM_THRESHOLD -1
+#define M_TOP_PAD -2
+#define M_MMAP_THRESHOLD -3
+#define M_MMAP_MAX -4
+#define M_SCANHEAP -5
+#define M_FILL
+
+
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
+#endif
+
+/*
+ M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+ to keep before releasing via malloc_trim in free().
+
+ Automatic trimming is mainly useful in long-lived programs.
+ Because trimming via sbrk can be slow on some systems, and can
+ sometimes be wasteful (in cases where programs immediately
+ afterward allocate more large chunks) the value should be high
+ enough so that your overall system performance would improve by
+ releasing.
+
+ The trim threshold and the mmap control parameters (see below)
+ can be traded off with one another. Trimming and mmapping are
+ two different ways of releasing unused memory back to the
+ system. Between these two, it is often possible to keep
+ system-level demands of a long-lived program down to a bare
+ minimum. For example, in one test suite of sessions measuring
+ the XF86 X server on Linux, using a trim threshold of 128K and a
+ mmap threshold of 192K led to near-minimal long term resource
+ consumption.
+
+ If you are using this malloc in a long-lived program, it should
+ pay to experiment with these values. As a rough guide, you
+ might set to a value close to the average size of a process
+ (program) running on your system. Releasing this much memory
+ would allow such a process to run in memory. Generally, it's
+ worth it to tune for trimming rather tham memory mapping when a
+ program undergoes phases where several large chunks are
+ allocated and released in ways that can reuse each other's
+ storage, perhaps mixed with phases where there are no such
+ chunks at all. And in well-behaved long-lived programs,
+ controlling release of large blocks via trimming versus mapping
+ is usually faster.
+
+ However, in most programs, these parameters serve mainly as
+ protection against the system-level effects of carrying around
+ massive amounts of unneeded memory. Since frequent calls to
+ sbrk, mmap, and munmap otherwise degrade performance, the default
+ parameters are set to relatively high values that serve only as
+ safeguards.
+
+ The default trim value is high enough to cause trimming only in
+ fairly extreme (by current memory consumption standards) cases.
+ It must be greater than page size to have any useful effect. To
+ disable trimming completely, you can set to (unsigned long)(-1);
+
+
+*/
+
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD (0)
+#endif
+
+/*
+ M_TOP_PAD is the amount of extra `padding' space to allocate or
+ retain whenever sbrk is called. It is used in two ways internally:
+
+ * When sbrk is called to extend the top of the arena to satisfy
+ a new malloc request, this much padding is added to the sbrk
+ request.
+
+ * When malloc_trim is called automatically from free(),
+ it is used as the `pad' argument.
+
+ In both cases, the actual amount of padding is rounded
+ so that the end of the arena is always a system page boundary.
+
+ The main reason for using padding is to avoid calling sbrk so
+ often. Having even a small pad greatly reduces the likelihood
+ that nearly every malloc request during program start-up (or
+ after trimming) will invoke sbrk, which needlessly wastes
+ time.
+
+ Automatic rounding-up to page-size units is normally sufficient
+ to avoid measurable overhead, so the default is 0. However, in
+ systems where sbrk is relatively slow, it can pay to increase
+ this value, at the expense of carrying around more memory than
+ the program needs.
+
+*/
+
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
+#endif
+
+/*
+
+ M_MMAP_THRESHOLD is the request size threshold for using mmap()
+ to service a request. Requests of at least this size that cannot
+ be allocated using already-existing space will be serviced via mmap.
+ (If enough normal freed space already exists it is used instead.)
+
+ Using mmap segregates relatively large chunks of memory so that
+ they can be individually obtained and released from the host
+ system. A request serviced through mmap is never reused by any
+ other request (at least not directly; the system may just so
+ happen to remap successive requests to the same locations).
+
+ Segregating space in this way has the benefit that mmapped space
+ can ALWAYS be individually released back to the system, which
+ helps keep the system level memory demands of a long-lived
+ program low. Mapped memory can never become `locked' between
+ other chunks, as can happen with normally allocated chunks, which
+ menas that even trimming via malloc_trim would not release them.
+
+ However, it has the disadvantages that:
+
+ 1. The space cannot be reclaimed, consolidated, and then
+ used to service later requests, as happens with normal chunks.
+ 2. It can lead to more wastage because of mmap page alignment
+ requirements
+ 3. It causes malloc performance to be more dependent on host
+ system memory management support routines which may vary in
+ implementation quality and may impose arbitrary
+ limitations. Generally, servicing a request via normal
+ malloc steps is faster than going through a system's mmap.
+
+ All together, these considerations should lead you to use mmap
+ only for relatively large requests.
+
+
+*/
+
+
+
+#ifndef DEFAULT_MMAP_MAX
+#if HAVE_MMAP
+#define DEFAULT_MMAP_MAX (64)
+#else
+#define DEFAULT_MMAP_MAX (0)
+#endif
+#endif
+
+/*
+ M_MMAP_MAX is the maximum number of requests to simultaneously
+ service using mmap. This parameter exists because:
+
+ 1. Some systems have a limited number of internal tables for
+ use by mmap.
+ 2. In most systems, overreliance on mmap can degrade overall
+ performance.
+ 3. If a program allocates many large regions, it is probably
+ better off using normal sbrk-based allocation routines that
+ can reclaim and reallocate normal heap memory. Using a
+ small value allows transition into this mode after the
+ first few allocations.
+
+ Setting to 0 disables all use of mmap. If HAVE_MMAP is not set,
+ the default value is 0, and attempts to set it to non-zero values
+ in mallopt will fail.
+*/
+
+
+
+
+/*
+
+ Special defines for linux libc
+
+ Except when compiled using these special defines for Linux libc
+ using weak aliases, this malloc is NOT designed to work in
+ multithreaded applications. No semaphores or other concurrency
+ control are provided to ensure that multiple malloc or free calls
+ don't run at the same time, which could be disasterous. A single
+ semaphore could be used across malloc, realloc, and free (which is
+ essentially the effect of the linux weak alias approach). It would
+ be hard to obtain finer granularity.
+
+*/
+
+
+#ifdef INTERNAL_LINUX_C_LIB
+
+#if __STD_C
+
+Void_t * __default_morecore_init (ptrdiff_t);
+Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init;
+
+#else
+
+Void_t * __default_morecore_init ();
+Void_t *(*__morecore)() = __default_morecore_init;
+
+#endif
+
+#define MORECORE (*__morecore)
+#define MORECORE_FAILURE 0
+#define MORECORE_CLEARS 1
+
+#else /* INTERNAL_LINUX_C_LIB */
+
+#if __STD_C
+/* extern Void_t* sbrk(ptrdiff_t);*/
+#else
+extern Void_t* sbrk();
+#endif
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE -1
+#endif
+
+#ifndef MORECORE_CLEARS
+#define MORECORE_CLEARS 0
+#endif
+
+#endif /* INTERNAL_LINUX_C_LIB */
+
+#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__)
+
+#define cALLOc __libc_calloc
+#define fREe __libc_free
+#define mALLOc __libc_malloc
+#define mEMALIGn __libc_memalign
+#define rEALLOc __libc_realloc
+#define vALLOc __libc_valloc
+#define pvALLOc __libc_pvalloc
+#define mALLINFo __libc_mallinfo
+#define mALLOPt __libc_mallopt
+
+#pragma weak calloc = __libc_calloc
+#pragma weak free = __libc_free
+#pragma weak cfree = __libc_free
+#pragma weak malloc = __libc_malloc
+#pragma weak memalign = __libc_memalign
+#pragma weak realloc = __libc_realloc
+#pragma weak valloc = __libc_valloc
+#pragma weak pvalloc = __libc_pvalloc
+#pragma weak mallinfo = __libc_mallinfo
+#pragma weak mallopt = __libc_mallopt
+
+#else
+
+#ifndef cALLOc
+#define cALLOc dlcalloc
+#endif
+#ifndef fREe
+#define fREe dlfree
+#endif
+#ifndef mALLOc
+#define mALLOc dlmalloc
+#endif
+#ifndef mEMALIGn
+#define mEMALIGn dlmemalign
+#endif
+#ifndef rEALLOc
+#define rEALLOc dlrealloc
+#endif
+#ifndef vALLOc
+#define vALLOc dlvalloc
+#endif
+#ifndef pvALLOc
+#define pvALLOc dlpvalloc
+#endif
+#ifndef mALLINFo
+#define mALLINFo dlmallinfo
+#endif
+#ifndef mALLOPt
+#define mALLOPt dlmallopt
+#endif
+
+#endif
+
+/* Public routines */
+
+#ifdef DEBUG2
+#define malloc(size) malloc_dbg(size, __FILE__, __LINE__)
+#define free(p) free_dbg(p, __FILE__, __LINE__)
+#define realloc(p, size) realloc_dbg(p, size, __FILE__, __LINE__)
+#define calloc(n, size) calloc_dbg(n, size, __FILE__, __LINE__)
+#define memalign(align, size) memalign_dbg(align, size, __FILE__, __LINE__)
+#define valloc(size) valloc_dbg(size, __FILE__, __LINE__)
+#define pvalloc(size) pvalloc_dbg(size, __FILE__, __LINE__)
+#define malloc_trim(pad) malloc_trim_dbg(pad, __FILE__, __LINE__)
+#define malloc_usable_size(p) malloc_usable_size_dbg(p, __FILE__, __LINE__)
+#define malloc_stats(void) malloc_stats_dbg(__FILE__, __LINE__)
+#define mallopt(flag, val) mallopt_dbg(flag, val, __FILE__, __LINE__)
+#define mallinfo(void) mallinfo_dbg(__FILE__, __LINE__)
+
+#if __STD_C
+Void_t* malloc_dbg(size_t, const char *, int);
+void free_dbg(Void_t*, const char *, int);
+Void_t* realloc_dbg(Void_t*, size_t, const char *, int);
+Void_t* calloc_dbg(size_t, size_t, const char *, int);
+Void_t* memalign_dbg(size_t, size_t, const char *, int);
+Void_t* valloc_dbg(size_t, const char *, int);
+Void_t* pvalloc_dbg(size_t, const char *, int);
+int malloc_trim_dbg(size_t, const char *, int);
+size_t malloc_usable_size_dbg(Void_t*, const char *, int);
+void malloc_stats_dbg(const char *, int);
+int mallopt_dbg(int, int, const char *, int);
+struct mallinfo mallinfo_dbg(const char *, int);
+#else
+Void_t* malloc_dbg();
+void free_dbg();
+Void_t* realloc_dbg();
+Void_t* calloc_dbg();
+Void_t* memalign_dbg();
+Void_t* valloc_dbg();
+Void_t* pvalloc_dbg();
+int malloc_trim_dbg();
+size_t malloc_usable_size_dbg();
+void malloc_stats_dbg();
+int mallopt_dbg();
+struct mallinfo mallinfo_dbg();
+#endif /* !__STD_C */
+
+#else /* !DEBUG2 */
+
+#if __STD_C
+
+Void_t* mALLOc(size_t);
+void fREe(Void_t*);
+Void_t* rEALLOc(Void_t*, size_t);
+Void_t* cALLOc(size_t, size_t);
+Void_t* mEMALIGn(size_t, size_t);
+Void_t* vALLOc(size_t);
+Void_t* pvALLOc(size_t);
+int malloc_trim(size_t);
+size_t malloc_usable_size(Void_t*);
+void malloc_stats(void);
+int mALLOPt(int, int);
+struct mallinfo mALLINFo(void);
+#else
+Void_t* mALLOc();
+void fREe();
+Void_t* rEALLOc();
+Void_t* cALLOc();
+Void_t* mEMALIGn();
+Void_t* vALLOc();
+Void_t* pvALLOc();
+int malloc_trim();
+size_t malloc_usable_size();
+void malloc_stats();
+int mALLOPt();
+struct mallinfo mALLINFo();
+#endif
+#endif /* !DEBUG2 */
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif
+
+/* ---------- To make a malloc.h, end cutting here ------------ */
+
+#ifdef DEBUG2
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#undef malloc
+#undef free
+#undef realloc
+#undef calloc
+#undef memalign
+#undef valloc
+#undef pvalloc
+#undef malloc_trim
+#undef malloc_usable_size
+#undef malloc_stats
+#undef mallopt
+#undef mallinfo
+
+#if __STD_C
+Void_t* mALLOc(size_t);
+void fREe(Void_t*);
+Void_t* rEALLOc(Void_t*, size_t);
+Void_t* cALLOc(size_t, size_t);
+Void_t* mEMALIGn(size_t, size_t);
+Void_t* vALLOc(size_t);
+Void_t* pvALLOc(size_t);
+int malloc_trim(size_t);
+size_t malloc_usable_size(Void_t*);
+void malloc_stats(void);
+int mALLOPt(int, int);
+struct mallinfo mALLINFo(void);
+#else
+Void_t* mALLOc();
+void fREe();
+Void_t* rEALLOc();
+Void_t* cALLOc();
+Void_t* mEMALIGn();
+Void_t* vALLOc();
+Void_t* pvALLOc();
+int malloc_trim();
+size_t malloc_usable_size();
+void malloc_stats();
+int mALLOPt();
+struct mallinfo mALLINFo();
+#endif
+
+#include <ctype.h> /* isprint() */
+#ifdef DEBUG3
+#include <stdlib.h> /* atexit() */
+#endif
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif
+
+#endif /* DEBUG2 */
+
+/*
+ Emulation of sbrk for WIN32
+ All code within the ifdef WIN32 is untested by me.
+*/
+
+
+#ifdef WIN32
+
+#define AlignPage(add) (((add) + (malloc_getpagesize-1)) & \
+ ~(malloc_getpagesize-1))
+
+/* resrve 64MB to insure large contiguous space */
+#define RESERVED_SIZE (1024*1024*64)
+#define NEXT_SIZE (2048*1024)
+#define TOP_MEMORY ((unsigned long)2*1024*1024*1024)
+
+struct GmListElement;
+typedef struct GmListElement GmListElement;
+
+struct GmListElement
+{
+ GmListElement* next;
+ void* base;
+};
+
+static GmListElement* head = 0;
+static unsigned int gNextAddress = 0;
+static unsigned int gAddressBase = 0;
+static unsigned int gAllocatedSize = 0;
+
+static
+GmListElement* makeGmListElement (void* bas)
+{
+ GmListElement* this;
+ this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement));
+ ASSERT (this);
+ if (this)
+ {
+ this->base = bas;
+ this->next = head;
+ head = this;
+ }
+ return this;
+}
+
+void gcleanup ()
+{
+ BOOL rval;
+ ASSERT ( (head == NULL) || (head->base == (void*)gAddressBase));
+ if (gAddressBase && (gNextAddress - gAddressBase))
+ {
+ rval = VirtualFree ((void*)gAddressBase,
+ gNextAddress - gAddressBase,
+ MEM_DECOMMIT);
+ ASSERT (rval);
+ }
+ while (head)
+ {
+ GmListElement* next = head->next;
+ rval = VirtualFree (head->base, 0, MEM_RELEASE);
+ ASSERT (rval);
+ LocalFree (head);
+ head = next;
+ }
+}
+
+static
+void* findRegion (void* start_address, unsigned long size)
+{
+ MEMORY_BASIC_INFORMATION info;
+ while ((unsigned long)start_address < TOP_MEMORY)
+ {
+ VirtualQuery (start_address, &info, sizeof (info));
+ if (info.State != MEM_FREE)
+ start_address = (char*)info.BaseAddress + info.RegionSize;
+ else if (info.RegionSize >= size)
+ return start_address;
+ else
+ start_address = (char*)info.BaseAddress + info.RegionSize;
+ }
+ return NULL;
+
+}
+
+
+void* wsbrk (long size)
+{
+ void* tmp;
+ if (size > 0)
+ {
+ if (gAddressBase == 0)
+ {
+ gAllocatedSize = max (RESERVED_SIZE, AlignPage (size));
+ gNextAddress = gAddressBase =
+ (unsigned int)VirtualAlloc (NULL, gAllocatedSize,
+ MEM_RESERVE, PAGE_NOACCESS);
+ } else if (AlignPage (gNextAddress + size) > (gAddressBase +
+gAllocatedSize))
+ {
+ long new_size = max (NEXT_SIZE, AlignPage (size));
+ void* new_address = (void*)(gAddressBase+gAllocatedSize);
+ do
+ {
+ new_address = findRegion (new_address, new_size);
+
+ if (new_address == 0)
+ return (void*)-1;
+
+ gAddressBase = gNextAddress =
+ (unsigned int)VirtualAlloc (new_address, new_size,
+ MEM_RESERVE, PAGE_NOACCESS);
+ // repeat in case of race condition
+ // The region that we found has been snagged
+ // by another thread
+ }
+ while (gAddressBase == 0);
+
+ ASSERT (new_address == (void*)gAddressBase);
+
+ gAllocatedSize = new_size;
+
+ if (!makeGmListElement ((void*)gAddressBase))
+ return (void*)-1;
+ }
+ if ((size + gNextAddress) > AlignPage (gNextAddress))
+ {
+ void* res;
+ res = VirtualAlloc ((void*)AlignPage (gNextAddress),
+ (size + gNextAddress -
+ AlignPage (gNextAddress)),
+ MEM_COMMIT, PAGE_READWRITE);
+ if (res == 0)
+ return (void*)-1;
+ }
+ tmp = (void*)gNextAddress;
+ gNextAddress = (unsigned int)tmp + size;
+ return tmp;
+ }
+ else if (size < 0)
+ {
+ unsigned int alignedGoal = AlignPage (gNextAddress + size);
+ /* Trim by releasing the virtual memory */
+ if (alignedGoal >= gAddressBase)
+ {
+ VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal,
+ MEM_DECOMMIT);
+ gNextAddress = gNextAddress + size;
+ return (void*)gNextAddress;
+ }
+ else
+ {
+ VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase,
+ MEM_DECOMMIT);
+ gNextAddress = gAddressBase;
+ return (void*)-1;
+ }
+ }
+ else
+ {
+ return (void*)gNextAddress;
+ }
+}
+
+#endif
+
+
+
+/*
+ Type declarations
+*/
+
+#ifdef DEBUG3
+# define MOATWIDTH 4 /* number of guard bytes at each end of
+ allocated region */
+# define MOATFILL 5 /* moat fill character */
+# define ALLOCFILL 1 /* fill char for allocated */
+# define FREEFILL 2 /* and freed regions */
+#endif
+
+typedef struct malloc_chunk
+{
+ INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
+ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
+ struct malloc_chunk* fd; /* double links -- used only if free. */
+ struct malloc_chunk* bk;
+#ifdef DEBUG3
+ const char *file; /* file and */
+ int line; /* line number of [re]allocation */
+ size_t pad; /* nr pad bytes at mem end, excluding moat */
+ int alloced; /* whether the chunk is allocated -- less prone
+ to segv than inuse(chunk) */
+ char moat[MOATWIDTH]; /* actual leading moat is last MOATWIDTH bytes
+ of chunk header; those bytes may follow this
+ field due to header alignment padding */
+#endif
+} Chunk;
+
+typedef Chunk* mchunkptr;
+
+/*
+
+ malloc_chunk details:
+
+ (The following includes lightly edited explanations by Colin Plumb.)
+
+ Chunks of memory are maintained using a `boundary tag' method as
+ described in e.g., Knuth or Standish. (See the paper by Paul
+ Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
+ survey of such techniques.) Sizes of free chunks are stored both
+ in the front of each chunk and at the end. This makes
+ consolidating fragmented chunks into bigger chunks very fast. The
+ size fields also hold bits representing whether chunks are free or
+ in use.
+
+ An allocated chunk looks like this:
+
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk, if allocated | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | User data starts here... .
+ . .
+ . (malloc_usable_space() bytes) .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+ Where "chunk" is the front of the chunk for the purpose of most of
+ the malloc code, but "mem" is the pointer that is returned to the
+ user. "Nextchunk" is the beginning of the next contiguous chunk.
+
+ Chunks always begin on even word boundries, so the mem portion
+ (which is returned to the user) is also on an even word boundary, and
+ thus double-word aligned.
+
+ Free chunks are stored in circular doubly-linked lists, and look like this:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space (may be 0 bytes long) .
+ . .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The P (PREV_INUSE) bit, stored in the unused low-order bit of the
+ chunk size (which is always a multiple of two words), is an in-use
+ bit for the *previous* chunk. If that bit is *clear*, then the
+ word before the current chunk size contains the previous chunk
+ size, and can be used to find the front of the previous chunk.
+ (The very first chunk allocated always has this bit set,
+ preventing access to non-existent (or non-owned) memory.)
+
+ Note that the `foot' of the current chunk is actually represented
+ as the prev_size of the NEXT chunk. (This makes it easier to
+ deal with alignments etc).
+
+ The two exceptions to all this are
+
+ 1. The special chunk `top', which doesn't bother using the
+ trailing size field since there is no
+ next contiguous chunk that would have to index off it. (After
+ initialization, `top' is forced to always exist. If it would
+ become less than MINSIZE bytes long, it is replenished via
+ malloc_extend_top.)
+
+ 2. Chunks allocated via mmap, which have the second-lowest-order
+ bit (IS_MMAPPED) set in their size fields. Because they are
+ never merged or traversed from any other chunk, they have no
+ foot size or inuse information.
+
+ Available chunks are kept in any of several places (all declared below):
+
+ * `av': An array of chunks serving as bin headers for consolidated
+ chunks. Each bin is doubly linked. The bins are approximately
+ proportionally (log) spaced. There are a lot of these bins
+ (128). This may look excessive, but works very well in
+ practice. All procedures maintain the invariant that no
+ consolidated chunk physically borders another one. Chunks in
+ bins are kept in size order, with ties going to the
+ approximately least recently used chunk.
+
+ The chunks in each bin are maintained in decreasing sorted order by
+ size. This is irrelevant for the small bins, which all contain
+ the same-sized chunks, but facilitates best-fit allocation for
+ larger chunks. (These lists are just sequential. Keeping them in
+ order almost never requires enough traversal to warrant using
+ fancier ordered data structures.) Chunks of the same size are
+ linked with the most recently freed at the front, and allocations
+ are taken from the back. This results in LRU or FIFO allocation
+ order, which tends to give each chunk an equal opportunity to be
+ consolidated with adjacent freed chunks, resulting in larger free
+ chunks and less fragmentation.
+
+ * `top': The top-most available chunk (i.e., the one bordering the
+ end of available memory) is treated specially. It is never
+ included in any bin, is used only if no other chunk is
+ available, and is released back to the system if it is very
+ large (see M_TRIM_THRESHOLD).
+
+ * `last_remainder': A bin holding only the remainder of the
+ most recently split (non-top) chunk. This bin is checked
+ before other non-fitting chunks, so as to provide better
+ locality for runs of sequentially allocated chunks.
+
+ * Implicitly, through the host system's memory mapping tables.
+ If supported, requests greater than a threshold are usually
+ serviced via calls to mmap, and then later released via munmap.
+
+*/
+
+
+
+
+
+
+/* sizes, alignments */
+
+#define SIZE_SZ sizeof(INTERNAL_SIZE_T)
+#define ALIGNMENT (SIZE_SZ + SIZE_SZ)
+#define ALIGN_MASK (ALIGNMENT - 1)
+#ifndef DEBUG3
+# define MEMOFFSET (2*SIZE_SZ)
+# define OVERHEAD SIZE_SZ
+# define MMAP_EXTRA SIZE_SZ /* for correct alignment */
+# define MINSIZE sizeof(Chunk)
+#else
+typedef union {
+ char strut[(sizeof(Chunk) - 1) / ALIGNMENT + 1][ALIGNMENT];
+ Chunk chunk;
+} PaddedChunk;
+# define MEMOFFSET sizeof(PaddedChunk)
+# define OVERHEAD (MEMOFFSET + MOATWIDTH)
+# define MMAP_EXTRA 0
+# define MINSIZE ((OVERHEAD + ALIGN_MASK) & ~ALIGN_MASK)
+#endif
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p) ((Void_t*)((char*)(p) + MEMOFFSET))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - MEMOFFSET))
+
+/* pad request bytes into a usable size, including overhead */
+
+#define request2size(req) \
+ ((long)((req) + OVERHEAD) < (long)MINSIZE ? MINSIZE : \
+ ((req) + OVERHEAD + ALIGN_MASK) & ~ALIGN_MASK)
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m) (((unsigned long)((m)) & ALIGN_MASK) == 0)
+
+
+
+
+/*
+ Physical chunk operations
+*/
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+
+#define PREV_INUSE 0x1
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+
+#define IS_MMAPPED 0x2
+
+/* Bits to mask off when extracting size */
+
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
+
+
+/* Ptr to next physical malloc_chunk. */
+
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
+
+/* Ptr to previous physical malloc_chunk */
+
+#define prev_chunk(p)\
+ ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
+
+
+/* Treat space at ptr + offset as a chunk */
+
+#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
+
+
+
+
+/*
+ Dealing with use bits
+*/
+
+/* extract p's inuse bit */
+
+#define inuse(p)\
+((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
+
+/* extract inuse bit of previous chunk */
+
+#define prev_inuse(p) ((p)->size & PREV_INUSE)
+
+/* check for mmap()'ed chunk */
+
+#if HAVE_MMAP
+# define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+#else
+# define chunk_is_mmapped(p) 0
+#endif
+
+/* set/clear chunk as in use without otherwise disturbing */
+
+#define set_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
+
+#define clear_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
+
+/* check/set/clear inuse bits in known places */
+
+#define inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
+
+
+
+
+/*
+ Dealing with size fields
+*/
+
+/* Get size, ignoring use bits */
+
+#define chunksize(p) ((p)->size & ~(SIZE_BITS))
+
+/* Set size at head, without disturbing its use bit */
+
+#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s)))
+
+/* Set size/use ignoring previous bits in header */
+
+#define set_head(p, s) ((p)->size = (s))
+
+/* Set size at footer (only when chunk is not in use) */
+
+#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
+
+
+
+
+
+/*
+ Bins
+
+ The bins, `av_' are an array of pairs of pointers serving as the
+ heads of (initially empty) doubly-linked lists of chunks, laid out
+ in a way so that each pair can be treated as if it were in a
+ malloc_chunk. (This way, the fd/bk offsets for linking bin heads
+ and chunks are the same).
+
+ Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+ 8 bytes apart. Larger bins are approximately logarithmically
+ spaced. (See the table below.) The `av_' array is never mentioned
+ directly in the code, but instead via bin access macros.
+
+ Bin layout:
+
+ 64 bins of size 8
+ 32 bins of size 64
+ 16 bins of size 512
+ 8 bins of size 4096
+ 4 bins of size 32768
+ 2 bins of size 262144
+ 1 bin of size what's left
+
+ There is actually a little bit of slop in the numbers in bin_index
+ for the sake of speed. This makes no difference elsewhere.
+
+ The special chunks `top' and `last_remainder' get their own bins,
+ (this is implemented via yet more trickery with the av_ array),
+ although `top' is never properly linked to its bin since it is
+ always handled specially.
+
+*/
+
+#define NAV 128 /* number of bins */
+
+typedef Chunk* mbinptr;
+
+/* access macros */
+
+#define bin_at(i) ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ))
+#define next_bin(b) ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr)))
+#define prev_bin(b) ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr)))
+
+/*
+ The first 2 bins are never indexed. The corresponding av_ cells are instead
+ used for bookkeeping. This is not to save space, but to simplify
+ indexing, maintain locality, and avoid some initialization tests.
+*/
+
+#define top (bin_at(0)->fd) /* The topmost chunk */
+#define last_remainder (bin_at(1)) /* remainder from last split */
+
+
+/*
+ Because top initially points to its own bin with initial
+ zero size, thus forcing extension on the first malloc request,
+ we avoid having any special code in malloc to check whether
+ it even exists yet. But we still need to in malloc_extend_top.
+*/
+
+#define initial_top ((mchunkptr)(bin_at(0)))
+
+/* Helper macro to initialize bins */
+
+#define IAV(i) bin_at(i), bin_at(i)
+
+static mbinptr av_[NAV * 2 + 2] = {
+ 0, 0,
+ IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7),
+ IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15),
+ IAV(16), IAV(17), IAV(18), IAV(19), IAV(20), IAV(21), IAV(22), IAV(23),
+ IAV(24), IAV(25), IAV(26), IAV(27), IAV(28), IAV(29), IAV(30), IAV(31),
+ IAV(32), IAV(33), IAV(34), IAV(35), IAV(36), IAV(37), IAV(38), IAV(39),
+ IAV(40), IAV(41), IAV(42), IAV(43), IAV(44), IAV(45), IAV(46), IAV(47),
+ IAV(48), IAV(49), IAV(50), IAV(51), IAV(52), IAV(53), IAV(54), IAV(55),
+ IAV(56), IAV(57), IAV(58), IAV(59), IAV(60), IAV(61), IAV(62), IAV(63),
+ IAV(64), IAV(65), IAV(66), IAV(67), IAV(68), IAV(69), IAV(70), IAV(71),
+ IAV(72), IAV(73), IAV(74), IAV(75), IAV(76), IAV(77), IAV(78), IAV(79),
+ IAV(80), IAV(81), IAV(82), IAV(83), IAV(84), IAV(85), IAV(86), IAV(87),
+ IAV(88), IAV(89), IAV(90), IAV(91), IAV(92), IAV(93), IAV(94), IAV(95),
+ IAV(96), IAV(97), IAV(98), IAV(99), IAV(100), IAV(101), IAV(102), IAV(103),
+ IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111),
+ IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119),
+ IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127)
+};
+
+
+
+/* field-extraction macros */
+
+#define first(b) ((b)->fd)
+#define last(b) ((b)->bk)
+
+/*
+ Indexing into bins
+*/
+
+#define bin_index(sz) \
+(((((unsigned long)(sz)) >> 9) == 0) ? (((unsigned long)(sz)) >> 3): \
+ ((((unsigned long)(sz)) >> 9) <= 4) ? 56 + (((unsigned long)(sz)) >> 6): \
+ ((((unsigned long)(sz)) >> 9) <= 20) ? 91 + (((unsigned long)(sz)) >> 9): \
+ ((((unsigned long)(sz)) >> 9) <= 84) ? 110 + (((unsigned long)(sz)) >> 12): \
+ ((((unsigned long)(sz)) >> 9) <= 340) ? 119 + (((unsigned long)(sz)) >> 15): \
+ ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \
+ 126)
+/*
+ bins for chunks < 512 are all spaced 8 bytes apart, and hold
+ identically sized chunks. This is exploited in malloc.
+*/
+
+#define MAX_SMALLBIN 63
+#define MAX_SMALLBIN_SIZE 512
+#define SMALLBIN_WIDTH 8
+
+#define smallbin_index(sz) (((unsigned long)(sz)) >> 3)
+
+/*
+ Requests are `small' if both the corresponding and the next bin are small
+*/
+
+#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH)
+
+
+
+/*
+ To help compensate for the large number of bins, a one-level index
+ structure is used for bin-by-bin searching. `binblocks' is a
+ one-word bitvector recording whether groups of BINBLOCKWIDTH bins
+ have any (possibly) non-empty bins, so they can be skipped over
+ all at once during during traversals. The bits are NOT always
+ cleared as soon as all bins in a block are empty, but instead only
+ when all are noticed to be empty during traversal in malloc.
+*/
+
+#define BINBLOCKWIDTH 4 /* bins per block */
+
+#define binblocks (bin_at(0)->size) /* bitvector of nonempty blocks */
+
+/* bin<->block macros */
+
+#define idx2binblock(ix) ((unsigned)1 << (ix / BINBLOCKWIDTH))
+#define mark_binblock(ii) (binblocks |= idx2binblock(ii))
+#define clear_binblock(ii) (binblocks &= ~(idx2binblock(ii)))
+
+
+
+
+
+/* Other static bookkeeping data */
+
+/* variables holding tunable values */
+
+static unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD;
+static unsigned long top_pad = DEFAULT_TOP_PAD;
+static unsigned int n_mmaps_max = DEFAULT_MMAP_MAX;
+static unsigned long mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+#ifdef DEBUG2
+static int scanheap = 1;
+#endif
+
+/* The first value returned from sbrk */
+static char* sbrk_base = (char*)(-1);
+
+/* The maximum memory obtained from system via sbrk */
+static unsigned long max_sbrked_mem = 0;
+
+/* The maximum via either sbrk or mmap */
+static unsigned long max_total_mem = 0;
+
+/* internal working copy of mallinfo */
+static struct mallinfo current_mallinfo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/* The total memory obtained from system via sbrk */
+#define sbrked_mem (current_mallinfo.arena)
+
+/* Tracking mmaps */
+
+static unsigned int n_mmaps = 0;
+static unsigned long mmapped_mem = 0;
+#if HAVE_MMAP
+static unsigned int max_n_mmaps = 0;
+static unsigned long max_mmapped_mem = 0;
+#endif
+
+
+
+/*
+ Debugging support
+*/
+
+#if DEBUG
+
+#ifndef DEBUG2
+# define unless(cond, err, p) assert(cond)
+#else
+# define unless(cond, err, p) do { if (!(cond)) malloc_err(err, p); } while (0)
+
+/*
+ * When debug_file is non-null, it and debug_line respectively contain the
+ * file and line number of the current invocation of malloc(), calloc(),
+ * realloc(), or free().
+ */
+static const char *debug_file = NULL;
+static int debug_line;
+
+/*
+ * Avoid dereferencing invalid chunk.file pointers by tracking the range of
+ * valid ones. Could add an "unallocated" flag to init_freed_chunk() for
+ * more protection, but that's probably not necessary.
+ */
+static const char *debug_file_min = (char *)~0;
+static const char *debug_file_max = NULL;
+
+static char *itos(int n)
+{
+#define NDIGITS (sizeof(int) * 3)
+ static char s[NDIGITS + 1];
+ int i = NDIGITS;
+ do {
+ s[--i] = '0' + n % 10;
+ n /= 10;
+ } while (n);
+ return s + i;
+#undef NDIGITS
+}
+
+static int recurs = 0;
+
+static void errprint(const char *file, int line, const char *err)
+{
+ if (recurs++) {
+ recurs--;
+ return;
+ }
+
+ if (file) {
+ write(2, file, strlen(file));
+ if (line) {
+ write(2, ":", 1);
+ write(2, itos(line), strlen(itos(line)));
+ }
+ write(2, ": ", 2);
+ }
+ write(2, err, strlen(err));
+ write(2, "\n", 1);
+ recurs--;
+}
+
+static void malloc_err(const char *err, mchunkptr p)
+{
+ /*
+ * Display ERR on stderr, accompanying it with the caller's file and line
+ * number if available. If P is non-null, also attempt to display the file
+ * and line number at which P was most recently [re]allocated.
+ *
+ * This function's name begins with "malloc_" to make setting debugger
+ * breakpoints here more convenient.
+ */
+ errprint(debug_file, debug_line, err);
+
+# ifndef DEBUG3
+ p = 0; /* avoid "unused param" warning */
+# else
+ if (p && p->file &&
+ /* avoid invalid pointers */
+ debug_file_min &&
+ p->file >= debug_file_min &&
+ p->file <= debug_file_max &&
+ /* try to avoid garbage file names */
+ isprint(*p->file))
+ errprint(p->file, p->line, "in block allocated here");
+# endif
+}
+
+#undef malloc
+#undef free
+#undef realloc
+#undef memalign
+#undef valloc
+#undef pvalloc
+#undef calloc
+#undef malloc_trim
+#undef malloc_usable_size
+#undef malloc_stats
+#undef mallopt
+#undef mallinfo
+
+static void malloc_update_mallinfo(void);
+
+/*
+ * Define front-end functions for all user-visible entry points that may
+ * trigger error().
+ */
+#define skel(retdecl, retassign, call, retstmt) \
+ retdecl \
+ debug_file = file; \
+ debug_line = line; \
+ if (debug_file < debug_file_min) \
+ debug_file_min = debug_file; \
+ if (debug_file > debug_file_max) \
+ debug_file_max = debug_file; \
+ if (scanheap) \
+ malloc_update_mallinfo(); \
+ retassign call; \
+ if (scanheap) \
+ malloc_update_mallinfo(); \
+ debug_file = NULL; \
+ retstmt
+
+/*
+ * The final letter of the names of the following macros is either r or v,
+ * indicating that the macro handles functions with or without a return value,
+ * respectively.
+ */
+# define skelr(rettype, call) \
+ skel(rettype ret;, ret = , call, return ret)
+/*
+ * AIX's xlc compiler doesn't like empty macro args, so specify useless but
+ * compilable retdecl, retassign, and retstmt args:
+ */
+#define skelv(call) \
+ skel(line += 0;, if (1), call, return)
+
+#define dbgargs const char *file, int line
+
+/*
+ * Front-end function definitions:
+ */
+Void_t* malloc_dbg(size_t bytes, dbgargs) {
+ skelr(Void_t*, malloc(bytes));
+}
+void free_dbg(Void_t *mem, dbgargs) {
+ skelv(free(mem));
+}
+Void_t* realloc_dbg(Void_t *oldmem, size_t bytes, dbgargs) {
+ skelr(Void_t*, realloc(oldmem, bytes));
+}
+Void_t* memalign_dbg(size_t alignment, size_t bytes, dbgargs) {
+ skelr(Void_t*, dlmemalign(alignment, bytes));
+}
+Void_t* valloc_dbg(size_t bytes, dbgargs) {
+ skelr(Void_t*, dlvalloc(bytes));
+}
+Void_t* pvalloc_dbg(size_t bytes, dbgargs) {
+ skelr(Void_t*, dlpvalloc(bytes));
+}
+Void_t* calloc_dbg(size_t n, size_t elem_size, dbgargs) {
+ skelr(Void_t*, calloc(n, elem_size));
+}
+int malloc_trim_dbg(size_t pad, dbgargs) {
+ skelr(int, malloc_trim(pad));
+}
+size_t malloc_usable_size_dbg(Void_t *mem, dbgargs) {
+ skelr(size_t, malloc_usable_size(mem));
+}
+void malloc_stats_dbg(dbgargs) {
+ skelv(malloc_stats());
+}
+int mallopt_dbg(int flag, int value, dbgargs) {
+ skelr(int, dlmallopt(flag, value));
+}
+struct mallinfo mallinfo_dbg(dbgargs) {
+ skelr(struct mallinfo, dlmallinfo());
+}
+
+#undef skel
+#undef skelr
+#undef skelv
+#undef dbgargs
+
+#endif /* DEBUG2 */
+
+/*
+ These routines make a number of assertions about the states
+ of data structures that should be true at all times. If any
+ are not true, it's very likely that a user program has somehow
+ trashed memory. (It's also possible that there is a coding error
+ in malloc. In which case, please report it!)
+*/
+
+#ifdef DEBUG3
+static int memtest(void *s, int c, size_t n)
+{
+ /*
+ * Return whether the N-byte memory region starting at S consists
+ * entirely of bytes with value C.
+ */
+ unsigned char *p = (unsigned char *)s;
+ size_t i;
+ for (i = 0; i < n; i++)
+ if (p[i] != (unsigned char)c)
+ return 0;
+ return 1;
+}
+#endif /* DEBUG3 */
+
+#ifndef DEBUG3
+#define check_moats(P)
+#else
+#define check_moats do_check_moats
+static void do_check_moats(mchunkptr p)
+{
+ INTERNAL_SIZE_T sz = chunksize(p);
+ unless(memtest((char *)chunk2mem(p) - MOATWIDTH, MOATFILL,
+ MOATWIDTH), "region underflow", p);
+ unless(memtest((char *)p + sz - MOATWIDTH - p->pad, MOATFILL,
+ MOATWIDTH + p->pad), "region overflow", p);
+}
+#endif /* DEBUG3 */
+
+#if __STD_C
+static void do_check_chunk(mchunkptr p)
+#else
+static void do_check_chunk(p) mchunkptr p;
+#endif
+{
+ /* Try to ensure legal addresses before accessing any chunk fields, in the
+ * hope of issuing an informative message rather than causing a segv.
+ *
+ * The following chunk_is_mmapped() call accesses p->size #if HAVE_MMAP.
+ * This is unavoidable without maintaining a record of mmapped regions.
+ */
+ if (!chunk_is_mmapped(p))
+ {
+ INTERNAL_SIZE_T sz;
+
+ unless((char*)p >= sbrk_base, "chunk precedes sbrk_base", p);
+ unless((char*)p + MINSIZE <= (char*)top + chunksize(top),
+ "chunk past sbrk area", p);
+
+ sz = chunksize(p);
+ if (p != top)
+ unless((char*)p + sz <= (char*)top, "chunk extends beyond top", p);
+ else
+ unless((char*)p + sz <= sbrk_base + sbrked_mem,
+ "chunk extends past sbrk area", p);
+ }
+ check_moats(p);
+}
+
+#if __STD_C
+static void do_check_free_chunk(mchunkptr p)
+#else
+static void do_check_free_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T sz = chunksize(p);
+ mchunkptr next = chunk_at_offset(p, sz);
+
+ do_check_chunk(p);
+
+ /* Check whether it claims to be free ... */
+ unless(!inuse(p), "free chunk marked inuse", p);
+
+ /* Unless a special marker, must have OK fields */
+ if ((long)sz >= (long)MINSIZE)
+ {
+ unless((sz & ALIGN_MASK) == 0, "freed size defies alignment", p);
+ unless(aligned_OK(chunk2mem(p)), "misaligned freed region", p);
+ /* ... matching footer field */
+ unless(next->prev_size == sz, "chunk size mismatch", p);
+ /* ... and is fully consolidated */
+ unless(prev_inuse(p), "free chunk not joined with prev", p);
+ unless(next == top || inuse(next), "free chunk not joined with next", p);
+
+ /* ... and has minimally sane links */
+ unless(p->fd->bk == p, "broken forward link", p);
+ unless(p->bk->fd == p, "broken backward link", p);
+ }
+ else /* markers are always of size SIZE_SZ */
+ unless(sz == SIZE_SZ, "invalid small chunk size", p);
+}
+
+#if __STD_C
+static void do_check_inuse_chunk(mchunkptr p)
+#else
+static void do_check_inuse_chunk(p) mchunkptr p;
+#endif
+{
+ mchunkptr next;
+ do_check_chunk(p);
+
+ if (chunk_is_mmapped(p))
+ return;
+
+ /* Check whether it claims to be in use ... */
+#ifdef DEBUG3
+ unless(p->alloced, "memory not allocated", p);
+#endif
+ unless(inuse(p), "memory not allocated", p);
+
+ /* ... and is surrounded by OK chunks.
+ Since more things can be checked with free chunks than inuse ones,
+ if an inuse chunk borders them and debug is on, it's worth doing them.
+ */
+ if (!prev_inuse(p))
+ {
+ mchunkptr prv = prev_chunk(p);
+ unless(next_chunk(prv) == p, "prev link scrambled", p);
+ do_check_free_chunk(prv);
+ }
+ next = next_chunk(p);
+ if (next == top)
+ {
+ unless(prev_inuse(next), "top chunk wrongly thinks prev is unused", p);
+ unless(chunksize(next) >= MINSIZE, "top chunk too small", p);
+ }
+ else if (!inuse(next))
+ do_check_free_chunk(next);
+}
+
+#if __STD_C
+static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+ INTERNAL_SIZE_T sz = chunksize(p);
+ long room = sz - s;
+
+ do_check_inuse_chunk(p);
+
+ /* Legal size ... */
+ unless((long)sz >= (long)MINSIZE, "chunk size too small", p);
+ unless((sz & ALIGN_MASK) == 0, "malloced size defies alignment", p);
+ unless(room >= 0, "chunk size too small for contents", p);
+ unless(room < (long)MINSIZE, "chunk size leaves too much spare room", p);
+
+ /* ... and alignment */
+ unless(aligned_OK(chunk2mem(p)), "misaligned malloced region", p);
+
+
+ /* ... and was allocated at front of an available chunk */
+ unless(prev_inuse(p), "malloced from the middle of a free chunk", p);
+}
+
+#ifdef DEBUG3
+static void init_alloced_chunk(mchunkptr p, size_t bytes)
+{
+ Void_t* mem = chunk2mem(p);
+ p->file = debug_file;
+ p->line = debug_line;
+ p->pad = chunksize(p) - OVERHEAD - bytes;
+ p->alloced = 1;
+ memset((char *)mem + bytes, MOATFILL, p->pad + MOATWIDTH);
+}
+
+static void do_init_malloced_chunk(mchunkptr p, size_t bytes)
+{
+ Void_t* mem = chunk2mem(p);
+ init_alloced_chunk(p, bytes);
+ memset((char *)mem - MOATWIDTH, MOATFILL, MOATWIDTH);
+ memset(mem, ALLOCFILL, bytes);
+}
+
+static void do_init_realloced_chunk(mchunkptr p, size_t bytes,
+ INTERNAL_SIZE_T oldsize)
+{
+ Void_t* mem = chunk2mem(p);
+ INTERNAL_SIZE_T newsize = chunksize(p);
+ init_alloced_chunk(p, bytes);
+ if (oldsize < newsize)
+ /* This incorrectly leaves the leading pad area of the old trailing moat
+ * set to MOATFILL rather than ALLOCFILL. An alternative is to save the
+ * old p->pad in rEALLOc() below and pass it to this function.
+ */
+ memset((char *)mem + oldsize - OVERHEAD, ALLOCFILL,
+ bytes - (oldsize - OVERHEAD));
+}
+
+static void do_check_freefill(mchunkptr p, long newsize,
+ INTERNAL_SIZE_T oldsize)
+{
+ /* The first newsize bytes of oldsize-byte chunk p are about to be
+ * allocated. Issue a warning if any freefill locations in p that are about
+ * to be overwritten do not contain the character FREEFILL.
+ */
+ size_t bytes, maxbytes;
+ if (newsize <= 0)
+ return;
+ bytes = newsize - MEMOFFSET /* don't check p's header */
+ + MEMOFFSET; /* header of split-off remainder */
+ maxbytes = oldsize - OVERHEAD;
+ if (bytes > maxbytes)
+ bytes = maxbytes;
+ unless(memtest(chunk2mem(p), FREEFILL, bytes),
+ "detected write to freed region", p);
+}
+
+static void do_init_freed_chunk(mchunkptr p, INTERNAL_SIZE_T freehead,
+ INTERNAL_SIZE_T freetail)
+{
+ /* freehead and freetail are the number of bytes at the beginning of p and
+ * end of p respectively that should already be initialized as free regions.
+ */
+ Void_t* mem = chunk2mem(p);
+ size_t size = chunksize(p);
+ size_t bytes = size - OVERHEAD;
+ p->pad = 0;
+ p->alloced = 0;
+ memset((char *)mem - MOATWIDTH, MOATFILL, MOATWIDTH);
+ memset((char *)mem + bytes, MOATFILL, MOATWIDTH);
+
+ /* To avoid terrible O(n^2) performance when free() repeatedly grows a free
+ * chunk, it's important not to free-fill regions that are already
+ * free-filled.
+ */
+ if (freehead + freetail < size) {
+ Void_t* start = !freehead ? mem : (char *)p + freehead - MOATWIDTH;
+ size_t len = (char *)p + size - (char *)start -
+ (!freetail ? MOATWIDTH : freetail - OVERHEAD);
+ memset(start, FREEFILL, len);
+ }
+}
+
+static void do_init_freeable_chunk(mchunkptr p)
+{
+ /* Arrange for the subsequent fREe(p) not to generate any warnings. */
+ init_alloced_chunk(p, chunksize(p) - OVERHEAD);
+ memset((char *)chunk2mem(p) - MOATWIDTH, MOATFILL, MOATWIDTH);
+}
+
+static void do_maximize_chunk(mchunkptr p)
+{
+ if (p->pad) {
+ Void_t* mem = chunk2mem(p);
+ size_t bytes = chunksize(p) - OVERHEAD - p->pad;
+ memset((char *)mem + bytes, ALLOCFILL, p->pad);
+ p->pad = 0;
+ }
+}
+
+static int do_check_init(void)
+{
+ /* Called from the first invocation of malloc_extend_top(), as detected by
+ * sbrk_base == -1. Return whether this function allocated any memory.
+ */
+ static int state = 0; /* 1 => initializing, 2 => initialized */
+ if (state == 1)
+ return 0;
+ unless(state == 0, "multiple calls to check_init", NULL);
+ state++;
+ atexit(malloc_update_mallinfo); /* calls malloc on WinNT */
+ return sbrk_base != (char *)-1;
+}
+#endif /* DEBUG3 */
+
+static mchunkptr lowest_chunk;
+
+#define check_free_chunk(P) do_check_free_chunk(P)
+#define check_inuse_chunk(P) do_check_inuse_chunk(P)
+#define check_chunk(P) do_check_chunk(P)
+#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N)
+#else /* !DEBUG */
+#define check_free_chunk(P)
+#define check_inuse_chunk(P)
+#define check_chunk(P)
+#define check_malloced_chunk(P,N)
+#endif /* !DEBUG */
+
+#ifdef DEBUG3
+#define check_init do_check_init
+#define init_malloced_chunk do_init_malloced_chunk
+#define init_realloced_chunk do_init_realloced_chunk
+#define check_freefill do_check_freefill
+#define init_freed_chunk do_init_freed_chunk
+#define init_freeable_chunk do_init_freeable_chunk
+#define maximize_chunk do_maximize_chunk
+#else
+#define check_init() 0
+#define init_malloced_chunk(P,B)
+#define init_realloced_chunk(P,B,O)
+#define check_freefill(P,N,O)
+#define init_freed_chunk(P,H,T)
+#define init_freeable_chunk(P)
+#define maximize_chunk(P)
+#endif /* !DEBUG3 */
+
+
+
+/*
+ Macro-based internal utilities
+*/
+
+
+/*
+ Linking chunks in bin lists.
+ Call these only with variables, not arbitrary expressions, as arguments.
+*/
+
+/*
+ Place chunk p of size s in its bin, in size order,
+ putting it ahead of others of same size.
+*/
+
+
+#define frontlink(P, S, IDX, BK, FD) \
+{ \
+ if (S < MAX_SMALLBIN_SIZE) \
+ { \
+ IDX = smallbin_index(S); \
+ mark_binblock(IDX); \
+ BK = bin_at(IDX); \
+ FD = BK->fd; \
+ P->bk = BK; \
+ P->fd = FD; \
+ FD->bk = BK->fd = P; \
+ } \
+ else \
+ { \
+ IDX = bin_index(S); \
+ BK = bin_at(IDX); \
+ FD = BK->fd; \
+ if (FD == BK) mark_binblock(IDX); \
+ else \
+ { \
+ while (FD != BK && S < chunksize(FD)) FD = FD->fd; \
+ BK = FD->bk; \
+ } \
+ P->bk = BK; \
+ P->fd = FD; \
+ FD->bk = BK->fd = P; \
+ } \
+}
+
+
+/* take a chunk off a list */
+
+#define unlink(P, BK, FD) \
+{ \
+ BK = P->bk; \
+ FD = P->fd; \
+ FD->bk = BK; \
+ BK->fd = FD; \
+} \
+
+/* Place p as the last remainder */
+
+#define link_last_remainder(P) \
+{ \
+ last_remainder->fd = last_remainder->bk = P; \
+ P->fd = P->bk = last_remainder; \
+}
+
+/* Clear the last_remainder bin */
+
+#define clear_last_remainder \
+ (last_remainder->fd = last_remainder->bk = last_remainder)
+
+
+
+
+
+
+/* Routines dealing with mmap(). */
+
+#if HAVE_MMAP
+
+#if __STD_C
+static mchunkptr mmap_chunk(size_t size)
+#else
+static mchunkptr mmap_chunk(size) size_t size;
+#endif
+{
+ size_t page_mask = malloc_getpagesize - 1;
+ mchunkptr p;
+
+#ifndef MAP_ANONYMOUS
+ static int fd = -1;
+#endif
+
+ if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */
+
+ size = (size + MMAP_EXTRA + page_mask) & ~page_mask;
+
+#ifdef MAP_ANONYMOUS
+ p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+#else /* !MAP_ANONYMOUS */
+ if (fd < 0)
+ {
+ fd = open("/dev/zero", O_RDWR);
+ if(fd < 0) return 0;
+ }
+ p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+#endif
+
+ if(p == (mchunkptr)-1) return 0;
+
+ n_mmaps++;
+ if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps;
+
+ /* We demand that eight bytes into a page must be 8-byte aligned. */
+ assert(aligned_OK(chunk2mem(p)));
+
+ /* The offset to the start of the mmapped region is stored
+ * in the prev_size field of the chunk; normally it is zero,
+ * but that can be changed in memalign().
+ */
+ p->prev_size = 0;
+ set_head(p, size|IS_MMAPPED);
+
+ mmapped_mem += size;
+ if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+ max_mmapped_mem = mmapped_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+ return p;
+}
+
+#if __STD_C
+static void munmap_chunk(mchunkptr p)
+#else
+static void munmap_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T size = chunksize(p);
+ int ret;
+
+ assert (chunk_is_mmapped(p));
+ assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+ assert((n_mmaps > 0));
+ assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0);
+
+ n_mmaps--;
+ mmapped_mem -= (size + p->prev_size);
+
+ ret = munmap((char *)p - p->prev_size, size + p->prev_size);
+
+ /* munmap returns non-zero on failure */
+ assert(ret == 0);
+}
+
+#if HAVE_MREMAP
+
+#if __STD_C
+static mchunkptr mremap_chunk(mchunkptr p, size_t new_size)
+#else
+static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size;
+#endif
+{
+ size_t page_mask = malloc_getpagesize - 1;
+ INTERNAL_SIZE_T offset = p->prev_size;
+ INTERNAL_SIZE_T size = chunksize(p);
+ char *cp;
+
+ assert (chunk_is_mmapped(p));
+ assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+ assert((n_mmaps > 0));
+ assert(((size + offset) & (malloc_getpagesize-1)) == 0);
+
+ new_size = (new_size + offset + MMAP_EXTRA + page_mask) & ~page_mask;
+
+ cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1);
+
+ if (cp == (char *)-1) return 0;
+
+ p = (mchunkptr)(cp + offset);
+
+ assert(aligned_OK(chunk2mem(p)));
+
+ assert(p->prev_size == offset);
+ set_head(p, (new_size - offset)|IS_MMAPPED);
+
+ mmapped_mem -= size + offset;
+ mmapped_mem += new_size;
+ if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+ max_mmapped_mem = mmapped_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+ return p;
+}
+
+#endif /* HAVE_MREMAP */
+
+#endif /* HAVE_MMAP */
+
+
+
+
+/*
+ Extend the top-most chunk by obtaining memory from system.
+ Main interface to sbrk (but see also malloc_trim).
+*/
+
+#if __STD_C
+static void malloc_extend_top(INTERNAL_SIZE_T nb)
+#else
+static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
+#endif
+{
+ char* lim; /* return value from sbrk */
+ INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */
+ INTERNAL_SIZE_T correction; /* bytes for 2nd sbrk call */
+ char* new_lim; /* return of 2nd sbrk call */
+ INTERNAL_SIZE_T top_size; /* new size of top chunk */
+
+ mchunkptr old_top = top; /* Record state of old top */
+ INTERNAL_SIZE_T old_top_size = chunksize(old_top);
+ char* old_end = (char*)(chunk_at_offset(old_top, old_top_size));
+
+ /* Pad request with top_pad plus minimal overhead */
+
+ INTERNAL_SIZE_T sbrk_size = nb + top_pad + MINSIZE;
+ unsigned long pagesz = malloc_getpagesize;
+
+ /* If not the first time through, round to preserve page boundary */
+ /* Otherwise, we need to correct to a page size below anyway. */
+ /* (We also correct below if an intervening foreign sbrk call.) */
+
+ if (sbrk_base != (char*)(-1))
+ sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1);
+
+ else if (check_init()) {
+ if (chunksize(top) - nb < (long)MINSIZE)
+ malloc_extend_top(nb);
+ return;
+ }
+
+ lim = (char*)(MORECORE (sbrk_size));
+
+ /* Fail if sbrk failed or if a foreign sbrk call killed our space */
+ if (lim == (char*)(MORECORE_FAILURE) ||
+ (lim < old_end && old_top != initial_top))
+ return;
+
+ sbrked_mem += sbrk_size;
+
+ if (lim == old_end) /* can just add bytes to current top */
+ {
+ top_size = sbrk_size + old_top_size;
+ set_head(top, top_size | PREV_INUSE);
+ }
+ else
+ {
+#ifdef SBRKDBG
+ INTERNAL_SIZE_T padding = (char *)sbrk (0) - (lim + sbrk_size);
+ sbrk_size += padding;
+ sbrked_mem += padding;
+#endif
+
+ if (sbrk_base == (char*)(-1)) /* First time through. Record base */
+ sbrk_base = lim;
+ else /* Someone else called sbrk(). Count those bytes as sbrked_mem. */
+ sbrked_mem += lim - (char*)old_end;
+
+ /* Guarantee alignment of first new chunk made from this space */
+ front_misalign = (unsigned long)chunk2mem(lim) & ALIGN_MASK;
+ if (front_misalign > 0)
+ {
+ correction = (ALIGNMENT) - front_misalign;
+ lim += correction;
+ }
+ else
+ correction = 0;
+
+ /* Guarantee the next brk will be at a page boundary */
+ correction += pagesz - ((unsigned long)(lim + sbrk_size) & (pagesz - 1));
+
+ /* Allocate correction */
+ new_lim = (char*)(MORECORE (correction));
+ if (new_lim == (char*)(MORECORE_FAILURE)) return;
+
+ sbrked_mem += correction;
+
+ top = (mchunkptr)lim;
+ top_size = new_lim - lim + correction;
+ set_head(top, top_size | PREV_INUSE);
+#if DEBUG
+ lowest_chunk = top;
+#endif
+
+#ifdef OTHER_SBRKS
+ if (old_top != initial_top)
+ {
+
+ /* There must have been an intervening foreign sbrk call. */
+ /* A double fencepost is necessary to prevent consolidation */
+
+ /* If not enough space to do this, then user did something very wrong */
+ if (old_top_size < MINSIZE)
+ {
+ set_head(top, PREV_INUSE); /* will force null return from malloc */
+ return;
+ }
+
+ old_top_size -= 2*SIZE_SZ;
+ chunk_at_offset(old_top, old_top_size )->size =
+ SIZE_SZ|PREV_INUSE;
+ chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size =
+ SIZE_SZ|PREV_INUSE;
+ set_head_size(old_top, old_top_size);
+ /* If possible, release the rest. */
+ if (old_top_size >= MINSIZE) {
+ init_freeable_chunk(old_top);
+ fREe(chunk2mem(old_top));
+ }
+ }
+#endif /* OTHER_SBRKS */
+ }
+
+ init_freed_chunk(top, old_top == initial_top ? old_top_size : 0, 0);
+
+ if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem)
+ max_sbrked_mem = sbrked_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+
+ /* We always land on a page boundary */
+ assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0);
+}
+
+
+
+
+/* Main public routines */
+
+
+/*
+ Malloc Algorthim:
+
+ The requested size is first converted into a usable form, `nb'.
+ This currently means to add 4 bytes overhead plus possibly more to
+ obtain 8-byte alignment and/or to obtain a size of at least
+ MINSIZE (currently 16 bytes), the smallest allocatable size.
+ (All fits are considered `exact' if they are within MINSIZE bytes.)
+
+ From there, the first successful of the following steps is taken:
+
+ 1. The bin corresponding to the request size is scanned, and if
+ a chunk of exactly the right size is found, it is taken.
+
+ 2. The most recently remaindered chunk is used if it is big
+ enough. This is a form of (roving) first fit, used only in
+ the absence of exact fits. Runs of consecutive requests use
+ the remainder of the chunk used for the previous such request
+ whenever possible. This limited use of a first-fit style
+ allocation strategy tends to give contiguous chunks
+ coextensive lifetimes, which improves locality and can reduce
+ fragmentation in the long run.
+
+ 3. Other bins are scanned in increasing size order, using a
+ chunk big enough to fulfill the request, and splitting off
+ any remainder. This search is strictly by best-fit; i.e.,
+ the smallest (with ties going to approximately the least
+ recently used) chunk that fits is selected.
+
+ 4. If large enough, the chunk bordering the end of memory
+ (`top') is split off. (This use of `top' is in accord with
+ the best-fit search rule. In effect, `top' is treated as
+ larger (and thus less well fitting) than any other available
+ chunk since it can be extended to be as large as necessary
+ (up to system limitations).
+
+ 5. If the request size meets the mmap threshold and the
+ system supports mmap, and there are few enough currently
+ allocated mmapped regions, and a call to mmap succeeds,
+ the request is allocated via direct memory mapping.
+
+ 6. Otherwise, the top of memory is extended by
+ obtaining more space from the system (normally using sbrk,
+ but definable to anything else via the MORECORE macro).
+ Memory is gathered from the system (in system page-sized
+ units) in a way that allows chunks obtained across different
+ sbrk calls to be consolidated, but does not require
+ contiguous memory. Thus, it should be safe to intersperse
+ mallocs with other sbrk calls.
+
+
+ All allocations are made from the the `lowest' part of any found
+ chunk. (The implementation invariant is that prev_inuse is
+ always true of any allocated chunk; i.e., that each allocated
+ chunk borders either a previously allocated and still in-use chunk,
+ or the base of its memory arena.)
+
+*/
+
+#if __STD_C
+Void_t* mALLOc(size_t bytes)
+#else
+Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+ mchunkptr victim; /* inspected/selected chunk */
+ INTERNAL_SIZE_T victim_size; /* its size */
+ int idx; /* index for bin traversal */
+ mbinptr bin; /* associated bin */
+ mchunkptr remainder; /* remainder from a split */
+ long remainder_size; /* its size */
+ int remainder_index; /* its bin index */
+ unsigned long block; /* block traverser bit */
+ int startidx; /* first bin of a traversed block */
+ mchunkptr fwd; /* misc temp for linking */
+ mchunkptr bck; /* misc temp for linking */
+ mbinptr q; /* misc temp */
+
+ INTERNAL_SIZE_T nb = request2size(bytes); /* padded request size; */
+
+ /* Check for exact match in a bin */
+
+ if (is_small_request(nb)) /* Faster version for small requests */
+ {
+ idx = smallbin_index(nb);
+
+ /* No traversal or size check necessary for small bins. */
+
+ q = bin_at(idx);
+ victim = last(q);
+
+ /* Also scan the next one, since it would have a remainder < MINSIZE */
+ if (victim == q)
+ {
+ q = next_bin(q);
+ victim = last(q);
+ }
+ if (victim != q)
+ {
+ victim_size = chunksize(victim);
+ unlink(victim, bck, fwd);
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_freefill(victim, victim_size, victim_size);
+ init_malloced_chunk(victim, bytes);
+ check_malloced_chunk(victim, nb);
+
+ return chunk2mem(victim);
+ }
+
+ idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */
+
+ }
+ else
+ {
+ idx = bin_index(nb);
+ bin = bin_at(idx);
+
+ for (victim = last(bin); victim != bin; victim = victim->bk)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* too big */
+ {
+ --idx; /* adjust to rescan below after checking last remainder */
+ break;
+ }
+
+ else if (remainder_size >= 0) /* exact fit */
+ {
+ unlink(victim, bck, fwd);
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_freefill(victim, victim_size, victim_size);
+ init_malloced_chunk(victim, bytes);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+
+ ++idx;
+
+ }
+
+ /* Try to use the last split-off remainder */
+
+ if ( (victim = last_remainder->fd) != last_remainder)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* re-split */
+ {
+ remainder = chunk_at_offset(victim, nb);
+ set_head(victim, nb | PREV_INUSE);
+ check_freefill(victim, nb, victim_size);
+ init_malloced_chunk(victim, bytes);
+ link_last_remainder(remainder);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ init_freed_chunk(remainder, remainder_size, 0);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ clear_last_remainder;
+
+ if (remainder_size >= 0) /* exhaust */
+ {
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_freefill(victim, victim_size, victim_size);
+ init_malloced_chunk(victim, bytes);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /* Else place in bin */
+
+ frontlink(victim, victim_size, remainder_index, bck, fwd);
+ }
+
+ /*
+ If there are any possibly nonempty big-enough blocks,
+ search for best fitting chunk by scanning bins in blockwidth units.
+ */
+
+ if ( (block = idx2binblock(idx)) <= binblocks)
+ {
+
+ /* Get to the first marked block */
+
+ if ( (block & binblocks) == 0)
+ {
+ /* force to an even block boundary */
+ idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH;
+ block <<= 1;
+ while ((block & binblocks) == 0)
+ {
+ idx += BINBLOCKWIDTH;
+ block <<= 1;
+ }
+ }
+
+ /* For each possibly nonempty block ... */
+ for (;;)
+ {
+ startidx = idx; /* (track incomplete blocks) */
+ q = bin = bin_at(idx);
+
+ /* For each bin in this block ... */
+ do
+ {
+ /* Find and use first big enough chunk ... */
+
+ for (victim = last(bin); victim != bin; victim = victim->bk)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* split */
+ {
+ remainder = chunk_at_offset(victim, nb);
+ set_head(victim, nb | PREV_INUSE);
+ check_freefill(victim, nb, victim_size);
+ unlink(victim, bck, fwd);
+ init_malloced_chunk(victim, bytes);
+ link_last_remainder(remainder);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ init_freed_chunk(remainder, remainder_size, 0);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ else if (remainder_size >= 0) /* take */
+ {
+ check_freefill(victim, victim_size, victim_size);
+ set_inuse_bit_at_offset(victim, victim_size);
+ unlink(victim, bck, fwd);
+ init_malloced_chunk(victim, bytes);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ }
+
+ bin = next_bin(bin);
+
+ } while ((++idx & (BINBLOCKWIDTH - 1)) != 0);
+
+ /* Clear out the block bit. */
+
+ do /* Possibly backtrack to try to clear a partial block */
+ {
+ if ((startidx & (BINBLOCKWIDTH - 1)) == 0)
+ {
+ binblocks &= ~block;
+ break;
+ }
+ --startidx;
+ q = prev_bin(q);
+ } while (first(q) == q);
+
+ /* Get to the next possibly nonempty block */
+
+ if ( (block <<= 1) <= binblocks && (block != 0) )
+ {
+ while ((block & binblocks) == 0)
+ {
+ idx += BINBLOCKWIDTH;
+ block <<= 1;
+ }
+ }
+ else
+ break;
+ }
+ }
+
+
+ /* Try to use top chunk */
+
+ /* Require that there be a remainder, ensuring top always exists */
+ if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+ {
+
+#if HAVE_MMAP
+ /* If big and would otherwise need to extend, try to use mmap instead */
+ if ((unsigned long)nb >= (unsigned long)mmap_threshold &&
+ (victim = mmap_chunk(nb)) != 0) {
+ init_malloced_chunk(victim, bytes);
+ return chunk2mem(victim);
+ }
+#endif
+
+ /* Try to extend */
+ malloc_extend_top(nb);
+ if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+ return 0; /* propagate failure */
+ }
+
+ victim = top;
+ set_head(victim, nb | PREV_INUSE);
+ check_freefill(victim, nb, nb + remainder_size);
+ init_malloced_chunk(victim, bytes);
+ top = chunk_at_offset(victim, nb);
+ set_head(top, remainder_size | PREV_INUSE);
+ init_freed_chunk(top, remainder_size, 0);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+
+}
+
+
+
+
+/*
+
+ free() algorithm :
+
+ cases:
+
+ 1. free(0) has no effect.
+
+ 2. If the chunk was allocated via mmap, it is release via munmap().
+
+ 3. If a returned chunk borders the current high end of memory,
+ it is consolidated into the top, and if the total unused
+ topmost memory exceeds the trim threshold, malloc_trim is
+ called.
+
+ 4. Other chunks are consolidated as they arrive, and
+ placed in corresponding bins. (This includes the case of
+ consolidating with the current `last_remainder').
+
+*/
+
+
+#if __STD_C
+void fREe(Void_t* mem)
+#else
+void fREe(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p; /* chunk corresponding to mem */
+ INTERNAL_SIZE_T hd; /* its head field */
+ INTERNAL_SIZE_T sz; /* its size */
+ int idx; /* its bin index */
+ mchunkptr next; /* next contiguous chunk */
+ INTERNAL_SIZE_T nextsz; /* its size */
+ INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+ int islr; /* track whether merging with last_remainder */
+
+ if (mem == 0) /* free(0) has no effect */
+ return;
+
+ p = mem2chunk(mem);
+ check_inuse_chunk(p);
+
+ hd = p->size;
+
+#if HAVE_MMAP
+ if (hd & IS_MMAPPED) /* release mmapped memory. */
+ {
+ munmap_chunk(p);
+ return;
+ }
+#endif
+
+ sz = hd & ~PREV_INUSE;
+ next = chunk_at_offset(p, sz);
+ nextsz = chunksize(next);
+ prevsz = 0; /* avoid compiler warnings */
+
+ if (next == top) /* merge with top */
+ {
+ sz += nextsz;
+
+ if (!(hd & PREV_INUSE)) /* consolidate backward */
+ {
+ prevsz = p->prev_size;
+ p = chunk_at_offset(p, -(long)prevsz);
+ sz += prevsz;
+ unlink(p, bck, fwd);
+ }
+
+ set_head(p, sz | PREV_INUSE);
+ top = p;
+ init_freed_chunk(top, !(hd & PREV_INUSE) ? prevsz : 0, nextsz);
+ if ((unsigned long)(sz) >= trim_threshold)
+ malloc_trim(top_pad);
+ return;
+ }
+
+ set_head(next, nextsz); /* clear inuse bit */
+
+ islr = 0;
+
+ if (!(hd & PREV_INUSE)) /* consolidate backward */
+ {
+ prevsz = p->prev_size;
+ p = chunk_at_offset(p, -(long)prevsz);
+ sz += prevsz;
+
+ if (p->fd == last_remainder) /* keep as last_remainder */
+ islr = 1;
+ else
+ unlink(p, bck, fwd);
+ }
+
+ if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */
+ {
+ sz += nextsz;
+
+ if (!islr && next->fd == last_remainder) /* re-insert last_remainder */
+ {
+ islr = 1;
+ link_last_remainder(p);
+ }
+ else
+ unlink(next, bck, fwd);
+ }
+
+
+ set_head(p, sz | PREV_INUSE);
+ set_foot(p, sz);
+ if (!islr)
+ frontlink(p, sz, idx, bck, fwd);
+ init_freed_chunk(p, !(hd & PREV_INUSE) ? prevsz : 0,
+ !inuse_bit_at_offset(next, nextsz) ? nextsz : 0);
+}
+
+
+
+
+
+/*
+
+ Realloc algorithm:
+
+ Chunks that were obtained via mmap cannot be extended or shrunk
+ unless HAVE_MREMAP is defined, in which case mremap is used.
+ Otherwise, if their reallocation is for additional space, they are
+ copied. If for less, they are just left alone.
+
+ Otherwise, if the reallocation is for additional space, and the
+ chunk can be extended, it is, else a malloc-copy-free sequence is
+ taken. There are several different ways that a chunk could be
+ extended. All are tried:
+
+ * Extending forward into following adjacent free chunk.
+ * Shifting backwards, joining preceding adjacent space
+ * Both shifting backwards and extending forward.
+ * Extending into newly sbrked space
+
+ Unless the #define realloc_ZERO_BYTES_FREES is set, realloc with a
+ size argument of zero (re)allocates a minimum-sized chunk.
+
+ If the reallocation is for less space, and the new request is for
+ a `small' (<512 bytes) size, then the newly unused space is lopped
+ off and freed.
+
+ The old unix realloc convention of allowing the last-free'd chunk
+ to be used as an argument to realloc is no longer supported.
+ I don't know of any programs still relying on this feature,
+ and allowing it would also allow too many other incorrect
+ usages of realloc to be sensible.
+
+
+*/
+
+
+#if __STD_C
+Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+
+ mchunkptr oldp; /* chunk corresponding to oldmem */
+ INTERNAL_SIZE_T oldsize; /* its size */
+
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ Void_t* newmem; /* corresponding user mem */
+
+ mchunkptr next; /* next contiguous chunk after oldp */
+ INTERNAL_SIZE_T nextsize; /* its size */
+
+ mchunkptr prev; /* previous contiguous chunk before oldp */
+ INTERNAL_SIZE_T prevsize; /* its size */
+
+ mchunkptr remainder; /* holds split off extra space from newp */
+ INTERNAL_SIZE_T remainder_size; /* its size */
+
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+
+#ifdef realloc_ZERO_BYTES_FREES
+ if (bytes == 0) { fREe(oldmem); return 0; }
+#endif
+
+
+ /* realloc of null is supposed to be same as malloc */
+ if (oldmem == 0) return mALLOc(bytes);
+
+ newp = oldp = mem2chunk(oldmem);
+ newsize = oldsize = chunksize(oldp);
+
+
+ nb = request2size(bytes);
+
+ check_inuse_chunk(oldp);
+
+#if HAVE_MMAP
+ if (chunk_is_mmapped(oldp))
+ {
+ if (oldsize - MMAP_EXTRA >= nb) {
+ init_realloced_chunk(oldp, bytes, oldsize);
+ return oldmem; /* do nothing */
+ }
+#if HAVE_MREMAP
+ newp = mremap_chunk(oldp, nb);
+ if (newp) {
+ init_realloced_chunk(newp, bytes, oldsize);
+ return chunk2mem(newp);
+ }
+#endif
+ /* Must alloc, copy, free. */
+ newmem = mALLOc(bytes);
+ if (newmem == 0) return 0; /* propagate failure */
+ malloc_COPY(newmem, oldmem, oldsize - OVERHEAD - MMAP_EXTRA);
+ munmap_chunk(oldp);
+ return newmem;
+ }
+#endif
+
+ if (oldsize < nb)
+ {
+
+ /* Try expanding forward */
+
+ next = chunk_at_offset(oldp, oldsize);
+ if (next == top || !inuse(next))
+ {
+ nextsize = chunksize(next);
+
+ /* Forward into top only if a remainder */
+ if (next == top)
+ {
+ if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE))
+ {
+ check_freefill(next, nb - oldsize, nextsize);
+ newsize += nextsize;
+ top = chunk_at_offset(oldp, nb);
+ set_head(top, (newsize - nb) | PREV_INUSE);
+ init_freed_chunk(top, newsize - nb, 0);
+ set_head_size(oldp, nb);
+ init_realloced_chunk(oldp, bytes, oldsize);
+ return chunk2mem(oldp);
+ }
+ }
+
+ /* Forward into next chunk */
+ else if (((long)(nextsize + newsize) >= (long)nb))
+ {
+ check_freefill(next, nb - oldsize, nextsize);
+ unlink(next, bck, fwd);
+ newsize += nextsize;
+ goto split;
+ }
+ }
+ else
+ {
+ next = 0;
+ nextsize = 0;
+ }
+
+ /* Try shifting backwards. */
+
+ if (!prev_inuse(oldp))
+ {
+ prev = prev_chunk(oldp);
+ prevsize = chunksize(prev);
+
+ /* try forward + backward first to save a later consolidation */
+
+ if (next != 0)
+ {
+ /* into top */
+ if (next == top)
+ {
+ if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE))
+ {
+ check_freefill(prev, nb, prevsize);
+ check_freefill(next, nb - (prevsize + newsize), nextsize);
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += prevsize + nextsize;
+ newmem = chunk2mem(newp);
+ malloc_COPY(newmem, oldmem, oldsize - OVERHEAD);
+ top = chunk_at_offset(newp, nb);
+ set_head(top, (newsize - nb) | PREV_INUSE);
+ init_freed_chunk(top, newsize - nb, 0);
+ set_head_size(newp, nb);
+ init_realloced_chunk(newp, bytes, oldsize);
+ return newmem;
+ }
+ }
+
+ /* into next chunk */
+ else if (((long)(nextsize + prevsize + newsize) >= (long)(nb)))
+ {
+ check_freefill(prev, nb, prevsize);
+ check_freefill(next, nb - (prevsize + newsize), nextsize);
+ unlink(next, bck, fwd);
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += nextsize + prevsize;
+ newmem = chunk2mem(newp);
+ malloc_COPY(newmem, oldmem, oldsize - OVERHEAD);
+ goto split;
+ }
+ }
+
+ /* backward only */
+ if (prev != 0 && (long)(prevsize + newsize) >= (long)nb)
+ {
+ check_freefill(prev, nb, prevsize);
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += prevsize;
+ newmem = chunk2mem(newp);
+ malloc_COPY(newmem, oldmem, oldsize - OVERHEAD);
+ goto split;
+ }
+ }
+
+ /* Must allocate */
+
+ newmem = mALLOc (bytes);
+
+ if (newmem == 0) /* propagate failure */
+ return 0;
+
+ /* Avoid copy if newp is next chunk after oldp. */
+ /* (This can only happen when new chunk is sbrk'ed.) */
+
+ if ( (newp = mem2chunk(newmem)) == next_chunk(oldp))
+ {
+ newsize += chunksize(newp);
+ newp = oldp;
+ goto split;
+ }
+
+ /* Otherwise copy, free, and exit */
+ malloc_COPY(newmem, oldmem, oldsize - OVERHEAD);
+ fREe(oldmem);
+ return newmem;
+ }
+
+
+ split: /* split off extra room in old or expanded chunk */
+
+ if (newsize - nb >= MINSIZE) /* split off remainder */
+ {
+ remainder = chunk_at_offset(newp, nb);
+ remainder_size = newsize - nb;
+ set_head_size(newp, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_inuse_bit_at_offset(remainder, remainder_size);
+ init_malloced_chunk(remainder, remainder_size - OVERHEAD);
+ fREe(chunk2mem(remainder)); /* let free() deal with it */
+ }
+ else
+ {
+ set_head_size(newp, newsize);
+ set_inuse_bit_at_offset(newp, newsize);
+ }
+
+ init_realloced_chunk(newp, bytes, oldsize);
+ check_inuse_chunk(newp);
+ return chunk2mem(newp);
+}
+
+
+
+
+/*
+
+ memalign algorithm:
+
+ memalign requests more than enough space from malloc, finds a spot
+ within that chunk that meets the alignment request, and then
+ possibly frees the leading and trailing space.
+
+ The alignment argument must be a power of two. This property is not
+ checked by memalign, so misuse may result in random runtime errors.
+
+ 8-byte alignment is guaranteed by normal malloc calls, so don't
+ bother calling memalign with an argument of 8 or less.
+
+ Overreliance on memalign is a sure way to fragment space.
+
+*/
+
+
+#if __STD_C
+Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+ char* m; /* memory returned by malloc call */
+ mchunkptr p; /* corresponding chunk */
+ char* lim; /* alignment point within p */
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */
+ mchunkptr remainder; /* spare room at end to split off */
+ long remainder_size; /* its size */
+
+ /* If need less alignment than we give anyway, just relay to malloc */
+
+ if (alignment <= ALIGNMENT) return mALLOc(bytes);
+
+ /* Otherwise, ensure that it is at least a minimum chunk size */
+
+ if (alignment < MINSIZE) alignment = MINSIZE;
+
+ /* Call malloc with worst case padding to hit alignment. */
+
+ nb = request2size(bytes);
+ m = (char*)mALLOc(nb + alignment + MINSIZE);
+
+ if (m == 0) return 0; /* propagate failure */
+
+ p = mem2chunk(m);
+
+ if ((((unsigned long)(m)) % alignment) == 0) /* aligned */
+ {
+ init_realloced_chunk(p, bytes, chunksize(p));
+ return chunk2mem(p); /* nothing more to do */
+ }
+ else /* misaligned */
+ {
+ /*
+ Find an aligned spot inside chunk.
+ Since we need to give back leading space in a chunk of at
+ least MINSIZE, if the first calculation places us at
+ a spot with less than MINSIZE leader, we can move to the
+ next aligned spot -- we've allocated enough total room so that
+ this is always possible.
+ */
+
+ lim = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) &
+ ~(alignment - 1));
+ if ((lim - (char*)p) < (long)MINSIZE) lim = lim + alignment;
+
+ newp = (mchunkptr)lim;
+ leadsize = lim - (char*)p;
+ newsize = chunksize(p) - leadsize;
+
+#if HAVE_MMAP
+ if(chunk_is_mmapped(p))
+ {
+ newp->prev_size = p->prev_size + leadsize;
+ set_head(newp, newsize|IS_MMAPPED);
+ init_malloced_chunk(newp, bytes);
+ return chunk2mem(newp);
+ }
+#endif
+
+ /* give back leader, use the rest */
+
+ set_head(newp, newsize | PREV_INUSE);
+ set_inuse_bit_at_offset(newp, newsize);
+ set_head_size(p, leadsize);
+ init_freeable_chunk(p);
+ fREe(chunk2mem(p));
+ p = newp;
+
+ assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0);
+ }
+
+ /* Also give back spare room at the end */
+
+ remainder_size = chunksize(p) - nb;
+
+ if (remainder_size >= (long)MINSIZE)
+ {
+ remainder = chunk_at_offset(p, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_head_size(p, nb);
+ init_freeable_chunk(remainder);
+ fREe(chunk2mem(remainder));
+ }
+
+ init_malloced_chunk(p, bytes);
+ check_inuse_chunk(p);
+ return chunk2mem(p);
+
+}
+
+
+
+
+/*
+ valloc just invokes memalign with alignment argument equal
+ to the page size of the system (or as near to this as can
+ be figured out from all the includes/defines above.)
+*/
+
+#if __STD_C
+Void_t* vALLOc(size_t bytes)
+#else
+Void_t* vALLOc(bytes) size_t bytes;
+#endif
+{
+ return mEMALIGn (malloc_getpagesize, bytes);
+}
+
+/*
+ pvalloc just invokes valloc for the nearest pagesize
+ that will accommodate request
+*/
+
+
+#if __STD_C
+Void_t* pvALLOc(size_t bytes)
+#else
+Void_t* pvALLOc(bytes) size_t bytes;
+#endif
+{
+ size_t pagesize = malloc_getpagesize;
+ return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1));
+}
+
+/*
+
+ calloc calls malloc, then zeroes out the allocated chunk.
+
+*/
+
+#if __STD_C
+Void_t* cALLOc(size_t n, size_t elem_size)
+#else
+Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
+#endif
+{
+ mchunkptr p;
+ INTERNAL_SIZE_T csz;
+
+ INTERNAL_SIZE_T sz = n * elem_size;
+
+ /* check if expand_top called, in which case don't need to clear */
+#if MORECORE_CLEARS
+ mchunkptr oldtop = top;
+ INTERNAL_SIZE_T oldtopsize = chunksize(top);
+#endif
+ Void_t* mem = mALLOc (sz);
+
+ if (mem == 0)
+ return 0;
+ else
+ {
+ p = mem2chunk(mem);
+
+ /* Two optional cases in which clearing not necessary */
+
+
+#if HAVE_MMAP
+ if (chunk_is_mmapped(p)) return mem;
+#endif
+
+ csz = chunksize(p);
+
+#if MORECORE_CLEARS
+ if (p == oldtop && csz > oldtopsize)
+ {
+ /* clear only the bytes from non-freshly-sbrked memory */
+ csz = oldtopsize;
+ }
+#endif
+
+ malloc_ZERO(mem, csz - OVERHEAD);
+ /* reinstate moat fill in pad region */
+ init_realloced_chunk(p, sz, chunksize(p));
+ return mem;
+ }
+}
+
+
+
+/*
+
+ Malloc_trim gives memory back to the system (via negative
+ arguments to sbrk) if there is unused memory at the `high' end of
+ the malloc pool. You can call this after freeing large blocks of
+ memory to potentially reduce the system-level memory requirements
+ of a program. However, it cannot guarantee to reduce memory. Under
+ some allocation patterns, some large free blocks of memory will be
+ locked between two used chunks, so they cannot be given back to
+ the system.
+
+ The `pad' argument to malloc_trim represents the amount of free
+ trailing space to leave untrimmed. If this argument is zero,
+ only the minimum amount of memory to maintain internal data
+ structures will be left (one page or less). Non-zero arguments
+ can be supplied to maintain enough trailing space to service
+ future expected allocations without having to re-obtain memory
+ from the system.
+
+ Malloc_trim returns 1 if it actually released any memory, else 0.
+
+*/
+
+#if __STD_C
+int dlmalloc_trim(size_t pad)
+#else
+int malloc_trim(pad) size_t pad;
+#endif
+{
+ long top_size; /* Amount of top-most memory */
+ long extra; /* Amount to release */
+ char* current_lim; /* address returned by pre-check sbrk call */
+ char* new_lim; /* address returned by negative sbrk call */
+
+ unsigned long pagesz = malloc_getpagesize;
+
+ top_size = chunksize(top);
+ extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
+
+ if (extra < (long)pagesz) /* Not enough memory to release */
+ return 0;
+
+ else
+ {
+#ifdef OTHER_SBRKS
+ /* Test to make sure no one else called sbrk */
+ current_lim = (char*)(MORECORE (0));
+ if (current_lim != (char*)(top) + top_size)
+ return 0; /* Apparently we don't own memory; must fail */
+
+ else
+#endif
+ {
+ new_lim = (char*)(MORECORE (-extra));
+
+ if (new_lim == (char*)(MORECORE_FAILURE)) /* sbrk failed? */
+ {
+ /* Try to figure out what we have */
+ current_lim = (char*)(MORECORE (0));
+ top_size = current_lim - (char*)top;
+ if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */
+ {
+ sbrked_mem = current_lim - sbrk_base;
+ set_head(top, top_size | PREV_INUSE);
+ init_freed_chunk(top, top_size, 0);
+ }
+ check_chunk(top);
+ return 0;
+ }
+
+ else
+ {
+ /* Success. Adjust top accordingly. */
+ set_head(top, (top_size - extra) | PREV_INUSE);
+ sbrked_mem -= extra;
+ init_freed_chunk(top, top_size - extra, 0);
+ check_chunk(top);
+ return 1;
+ }
+ }
+ }
+}
+
+
+
+/*
+ malloc_usable_size:
+
+ This routine tells you how many bytes you can actually use in an
+ allocated chunk, which may be more than you requested (although
+ often not). You can use this many bytes without worrying about
+ overwriting other allocated objects. Not a particularly great
+ programming practice, but still sometimes useful.
+
+*/
+
+#if __STD_C
+size_t dlmalloc_usable_size(Void_t* mem)
+#else
+size_t malloc_usable_size(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p;
+ if (mem == 0)
+ return 0;
+ else
+ {
+ p = mem2chunk(mem);
+ check_inuse_chunk(p);
+ maximize_chunk(p);
+ if(!chunk_is_mmapped(p))
+ {
+ if (!inuse(p)) return 0;
+ return chunksize(p) - OVERHEAD;
+ }
+ return chunksize(p) - OVERHEAD - MMAP_EXTRA;
+ }
+}
+
+
+
+
+/* Utility to update current_mallinfo for malloc_stats and mallinfo() */
+
+static void malloc_update_mallinfo(void)
+{
+ int i;
+ mbinptr b;
+ mchunkptr p;
+#if DEBUG
+ mchunkptr q;
+#endif
+
+ INTERNAL_SIZE_T avail = chunksize(top);
+ int navail = avail >= MINSIZE ? 1 : 0;
+ check_freefill(top, avail, avail);
+
+#if DEBUG
+ if (lowest_chunk)
+ for (p = lowest_chunk;
+ p < top && inuse(p) && chunksize(p) >= MINSIZE;
+ p = next_chunk(p))
+ check_inuse_chunk(p);
+#endif
+
+ for (i = 1; i < NAV; ++i)
+ {
+ b = bin_at(i);
+ for (p = last(b); p != b; p = p->bk)
+ {
+#if DEBUG
+ check_free_chunk(p);
+ check_freefill(p, chunksize(p), chunksize(p));
+ for (q = next_chunk(p);
+ q < top && inuse(q) && chunksize(q) >= MINSIZE;
+ q = next_chunk(q))
+ check_inuse_chunk(q);
+#endif
+ avail += chunksize(p);
+ navail++;
+ }
+ }
+
+ current_mallinfo.ordblks = navail;
+ current_mallinfo.uordblks = sbrked_mem - avail;
+ current_mallinfo.fordblks = avail;
+ current_mallinfo.hblks = n_mmaps;
+ current_mallinfo.hblkhd = mmapped_mem;
+ current_mallinfo.keepcost = chunksize(top);
+
+}
+
+
+
+/*
+
+ malloc_stats:
+
+ Prints on stderr the amount of space obtain from the system (both
+ via sbrk and mmap), the maximum amount (which may be more than
+ current if malloc_trim and/or munmap got called), the maximum
+ number of simultaneous mmap regions used, and the current number
+ of bytes allocated via malloc (or realloc, etc) but not yet
+ freed. (Note that this is the number of bytes allocated, not the
+ number requested. It will be larger than the number requested
+ because of alignment and bookkeeping overhead.)
+
+*/
+
+void dlmalloc_stats(void)
+{
+ malloc_update_mallinfo();
+ fprintf(stderr, "max system bytes = %10u\n",
+ (unsigned int)(max_total_mem));
+ fprintf(stderr, "system bytes = %10u\n",
+ (unsigned int)(sbrked_mem + mmapped_mem));
+ fprintf(stderr, "in use bytes = %10u\n",
+ (unsigned int)(current_mallinfo.uordblks + mmapped_mem));
+#if HAVE_MMAP
+ fprintf(stderr, "max mmap regions = %10u\n",
+ (unsigned int)max_n_mmaps);
+#endif
+}
+
+/*
+ mallinfo returns a copy of updated current mallinfo.
+*/
+
+struct mallinfo mALLINFo(void)
+{
+ malloc_update_mallinfo();
+ return current_mallinfo;
+}
+
+
+
+
+/*
+ mallopt:
+
+ mallopt is the general SVID/XPG interface to tunable parameters.
+ The format is to provide a (parameter-number, parameter-value) pair.
+ mallopt then sets the corresponding parameter to the argument
+ value if it can (i.e., so long as the value is meaningful),
+ and returns 1 if successful else 0.
+
+ See descriptions of tunable parameters above.
+
+*/
+
+#if __STD_C
+int mALLOPt(int param_number, int value)
+#else
+int mALLOPt(param_number, value) int param_number; int value;
+#endif
+{
+ switch(param_number)
+ {
+ case M_TRIM_THRESHOLD:
+ trim_threshold = value; return 1;
+ case M_TOP_PAD:
+ top_pad = value; return 1;
+ case M_MMAP_THRESHOLD:
+ mmap_threshold = value; return 1;
+ case M_MMAP_MAX:
+#if HAVE_MMAP
+ n_mmaps_max = value; return 1;
+#else
+ if (value != 0) return 0; else n_mmaps_max = value; return 1;
+#endif
+ case M_SCANHEAP:
+#ifdef DEBUG2
+ scanheap = value;
+#endif
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/*
+
+History:
+
+ V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
+ * Added pvalloc, as recommended by H.J. Liu
+ * Added 64bit pointer support mainly from Wolfram Gloger
+ * Added anonymously donated WIN32 sbrk emulation
+ * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+ * malloc_extend_top: fix mask error that caused wastage after
+ foreign sbrks
+ * Add linux mremap support code from HJ Liu
+
+ V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
+ * Integrated most documentation with the code.
+ * Add support for mmap, with help from
+ Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Use last_remainder in more cases.
+ * Pack bins using idea from colin@nyx10.cs.du.edu
+ * Use ordered bins instead of best-fit threshhold
+ * Eliminate block-local decls to simplify tracing and debugging.
+ * Support another case of realloc via move into top
+ * Fix error occuring when initial sbrk_base not word-aligned.
+ * Rely on page size for units instead of SBRK_UNIT to
+ avoid surprises about sbrk alignment conventions.
+ * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+ (raymond@es.ele.tue.nl) for the suggestion.
+ * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+ * More precautions for cases where other routines call sbrk,
+ courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Added macros etc., allowing use in linux libc from
+ H.J. Lu (hjl@gnu.ai.mit.edu)
+ * Inverted this history list
+
+ V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
+ * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+ * Removed all preallocation code since under current scheme
+ the work required to undo bad preallocations exceeds
+ the work saved in good cases for most test programs.
+ * No longer use return list or unconsolidated bins since
+ no scheme using them consistently outperforms those that don't
+ given above changes.
+ * Use best fit for very large chunks to prevent some worst-cases.
+ * Added some support for debugging
+
+ V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
+ * Removed footers when chunks are in use. Thanks to
+ Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+ V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
+ * Added malloc_trim, with help from Wolfram Gloger
+ (wmglo@Dent.MED.Uni-Muenchen.DE).
+
+ V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
+
+ V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
+ * realloc: try to expand in both directions
+ * malloc: swap order of clean-bin strategy;
+ * realloc: only conditionally expand backwards
+ * Try not to scavenge used bins
+ * Use bin counts as a guide to preallocation
+ * Occasionally bin return list chunks in first scan
+ * Add a few optimizations from colin@nyx10.cs.du.edu
+
+ V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
+ * faster bin computation & slightly different binning
+ * merged all consolidations to one part of malloc proper
+ (eliminating old malloc_find_space & malloc_clean_bin)
+ * Scan 2 returns chunks (not just 1)
+ * Propagate failure in realloc if malloc returns 0
+ * Add stuff to allow compilation on non-ANSI compilers
+ from kpv@research.att.com
+
+ V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
+ * removed potential for odd address access in prev_chunk
+ * removed dependency on getpagesize.h
+ * misc cosmetics and a bit more internal documentation
+ * anticosmetics: mangled names in macros to evade debugger strangeness
+ * tested on sparc, hp-700, dec-mips, rs6000
+ with gcc & native cc (hp, dec only) allowing
+ Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+ Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
+ * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+ structure of old version, but most details differ.)
+
+*/
diff --git a/winsup/cygwin/dlmalloc.h b/winsup/cygwin/dlmalloc.h
new file mode 100644
index 00000000000..b8d7ebeeb48
--- /dev/null
+++ b/winsup/cygwin/dlmalloc.h
@@ -0,0 +1,93 @@
+
+/*
+ * Header file for BBCized version of Doug Lea's malloc.c, automatically
+ * generated by
+ * /source/prod/libbbc/compat/dlmalloc/cvt
+ * from
+ * /source/prod/libbbc/compat/dlmalloc/malloc.c
+ *
+ * bbclabel: autogenerated
+ */
+#define _INCLUDE_MALLOC_H_ 1
+void malloc_outofmem(void (*)(void));
+
+
+struct mallinfo {
+ int arena; /* total space allocated from system */
+ int ordblks; /* number of non-inuse chunks */
+ int smblks; /* unused -- always zero */
+ int hblks; /* number of mmapped regions */
+ int hblkhd; /* total space in mmapped regions */
+ int usmblks; /* unused -- always zero */
+ int fsmblks; /* unused -- always zero */
+ int uordblks; /* total allocated space */
+ int fordblks; /* total non-inuse space */
+ int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+
+#define M_MXFAST 1 /* UNUSED in this malloc */
+#define M_NLBLKS 2 /* UNUSED in this malloc */
+#define M_GRAIN 3 /* UNUSED in this malloc */
+#define M_KEEP 4 /* UNUSED in this malloc */
+
+
+#define M_TRIM_THRESHOLD -1
+#define M_TOP_PAD -2
+#define M_MMAP_THRESHOLD -3
+#define M_MMAP_MAX -4
+#define M_SCANHEAP -5
+#define M_FILL
+
+#ifdef MALLOC_DEBUG
+
+#define dmalloc(size) malloc_dbg(size, __FILE__, __LINE__)
+#define dfree(p) free_dbg(p, __FILE__, __LINE__)
+#define drealloc(p, size) realloc_dbg(p, size, __FILE__, __LINE__)
+#define dcalloc(n, size) calloc_dbg(n, size, __FILE__, __LINE__)
+#define dmemalign(align, size) memalign_dbg(align, size, __FILE__, __LINE__)
+#define dvalloc(size) valloc_dbg(size, __FILE__, __LINE__)
+#define dpvalloc(size) pvalloc_dbg(size, __FILE__, __LINE__)
+#define dmalloc_trim(pad) malloc_trim_dbg(pad, __FILE__, __LINE__)
+#define dmalloc_usable_size(p) malloc_usable_size_dbg(p, __FILE__, __LINE__)
+#define dmalloc_stats() malloc_stats_dbg(__FILE__, __LINE__)
+#define dmallopt(flag, val) mallopt_dbg(flag, val, __FILE__, __LINE__)
+#define dmallinfo() mallinfo_dbg(__FILE__, __LINE__)
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void* malloc_dbg(size_t, const char *, int);
+void free_dbg(void*, const char *, int);
+void* realloc_dbg(void*, size_t, const char *, int);
+void* calloc_dbg(size_t, size_t, const char *, int);
+void* memalign_dbg(size_t, size_t, const char *, int);
+void* valloc_dbg(size_t, const char *, int);
+void* pvalloc_dbg(size_t, const char *, int);
+int malloc_trim_dbg(size_t, const char *, int);
+size_t malloc_usable_size_dbg(void*, const char *, int);
+void malloc_stats_dbg(const char *, int);
+int mallopt_dbg(int, int, const char *, int);
+struct mallinfo mallinfo_dbg(const char *, int);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MALLOC_DEBUG */
+
+#ifndef MALLOC_DEBUG
+
+void* malloc(size_t);
+void free(void*);
+void* realloc(void*, size_t);
+void* calloc(size_t, size_t);
+void* memalign(size_t, size_t);
+void* valloc(size_t);
+void* pvalloc(size_t);
+int malloc_trim(size_t);
+size_t malloc_usable_size(void*);
+void malloc_stats(void);
+int mallopt(int, int);
+struct mallinfo mallinfo(void);
+#endif /* !MALLOC_DEBUG */
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 1732165256b..c63ed20584e 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -731,18 +731,6 @@ signal_fixup_after_fork ()
sigproc_init ();
}
-void __stdcall
-signal_fixup_after_exec ()
-{
- /* Set up child's signal handlers */
- for (int i = 0; i < NSIG; i++)
- {
- myself->getsig (i).sa_mask = 0;
- if (myself->getsig (i).sa_handler != SIG_IGN)
- myself->getsig (i).sa_handler = SIG_DFL;
- }
-}
-
static int interrupt_on_return (sigthread *, int, void *, struct sigaction&) __attribute__((regparm(3)));
static int
interrupt_on_return (sigthread *th, int sig, void *handler, struct sigaction& siga)
@@ -785,10 +773,9 @@ setup_handler (int sig, void *handler, struct sigaction& siga)
CONTEXT cx;
bool interrupted = false;
sigthread *th = NULL; // Initialization needed to shut up gcc
- int prio = INFINITE;
if (sigsave.sig)
- goto set_pending;
+ goto out;
for (int i = 0; i < CALL_HANDLER_RETRY; i++)
{
@@ -823,7 +810,18 @@ setup_handler (int sig, void *handler, struct sigaction& siga)
SuspendThread on itself then just queue the signal. */
EnterCriticalSection (&mainthread.lock);
+#ifndef DEBUGGING
sigproc_printf ("suspending mainthread");
+#else
+ cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
+ if (!GetThreadContext (hth, &cx))
+ memset (&cx, 0, sizeof cx);
+#if 0
+ if ((cx.Eip & 0xff000000) == 0x77000000)
+ try_to_debug ();
+#endif
+ sigproc_printf ("suspending mainthread PC %p", cx.Eip);
+#endif
res = SuspendThread (hth);
/* Just release the lock now since we hav suspended the main thread and it
definitely can't be grabbing it now. This will have to change, of course,
@@ -866,13 +864,6 @@ setup_handler (int sig, void *handler, struct sigaction& siga)
}
}
- if ((DWORD) prio != INFINITE)
- {
- /* Reset the priority so we can finish this off quickly. */
- SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY);
- prio = INFINITE;
- }
-
if (th)
{
interrupted = interrupt_on_return (th, sig, handler, siga);
@@ -888,20 +879,11 @@ setup_handler (int sig, void *handler, struct sigaction& siga)
if (interrupted)
break;
- if ((DWORD) prio != INFINITE && !mainthread.frame)
- prio = low_priority_sleep (SLEEP_0_STAY_LOW);
sigproc_printf ("couldn't interrupt. trying again.");
}
- set_pending:
- if (interrupted)
- {
- if ((DWORD) prio != INFINITE)
- SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY);
- sigproc_printf ("signal successfully delivered");
- }
-
- sigproc_printf ("returning %d", interrupted);
+out:
+ sigproc_printf ("signal %d %sdelivered", sig, interrupted ? "" : "not ");
return interrupted;
}
#endif /* i386 */
@@ -1225,7 +1207,9 @@ _sigreturn: \n\
cmpl $0,%4 # Did a signal come in? \n\
jz 1f # No, if zero \n\
movl %2,%%eax \n\
- movl %%eax,36(%%esp) # Restore return address \n\
+ movl %8,%%ebx # Where return address lives \n\
+ movl %%eax,(%%ebx) # Restore return address of \n\
+ # most recent caller \n\
jmp 3f \n\
\n\
1: popl %%eax # saved errno \n\
@@ -1272,10 +1256,10 @@ _sigdelayed0: \n\
popl %%eax \n\
jmp *%%eax \n\
__no_sig_end: \n\
-" : "=m" (sigsave.sig): "X" ((char *) &_impure_ptr->_errno),
- "g" (sigsave.retaddr), "g" (sigsave.oldmask), "g" (sigsave.sig),
- "g" (sigsave.func), "g" (sigsave.saved_errno), "g" (sigsave.newmask),
- "g" (sigsave.retaddr_on_stack)
+" : "=m" (sigsave.sig)/*0*/: "X" ((char *) &_impure_ptr->_errno)/*1*/,
+ "g" (sigsave.retaddr)/*2*/, "g" (sigsave.oldmask)/*3*/, "g" (sigsave.sig)/*4*/,
+ "g" (sigsave.func)/*5*/, "g" (sigsave.saved_errno)/*6*/, "g" (sigsave.newmask)/*7*/,
+ "g" (sigsave.retaddr_on_stack)/*8*/
);
}
}
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index f9b822522b9..9ecc9edda5c 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -213,7 +213,7 @@ fhandler_base::raw_read (void *ptr, size_t& ulen)
int prio = 0; /* ditto */
DWORD len = ulen;
- (ssize_t) ulen = -1;
+ ulen = (size_t) -1;
if (read_state)
{
h = GetCurrentThread ();
diff --git a/winsup/cygwin/heap.cc b/winsup/cygwin/heap.cc
index 428399320bb..60cbb4fe134 100644
--- a/winsup/cygwin/heap.cc
+++ b/winsup/cygwin/heap.cc
@@ -139,7 +139,6 @@ sbrk (int n)
/* Couldn't allocate memory. Maybe we can reserve some more.
Reserve either the maximum of the standard cygwin_shared->heap_chunk_size ()
or the requested amount. Then attempt to actually allocate it. */
-
if ((newbrksize = cygheap->user_heap.chunk) < commitbytes)
newbrksize = commitbytes;
@@ -147,7 +146,7 @@ sbrk (int n)
|| VirtualAlloc (cygheap->user_heap.top, newbrksize = commitbytes, MEM_RESERVE, PAGE_NOACCESS))
&& VirtualAlloc (cygheap->user_heap.top, commitbytes, MEM_COMMIT, PAGE_READWRITE) != NULL)
{
- (char *) cygheap->user_heap.max += newbrksize;
+ (char *) cygheap->user_heap.max += pround (newbrksize);
goto good;
}
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index 8a6354ddcad..b99b0640421 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -42,7 +42,7 @@ details. */
changes to the DLL and is mainly informative in nature. */
#define CYGWIN_VERSION_DLL_MAJOR 1005
-#define CYGWIN_VERSION_DLL_MINOR 3
+#define CYGWIN_VERSION_DLL_MINOR 4
/* Major numbers before CYGWIN_VERSION_DLL_EPOCH are
incompatible. */
diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h
index dccff206862..e117175e0c2 100644
--- a/winsup/cygwin/include/sys/cygwin.h
+++ b/winsup/cygwin/include/sys/cygwin.h
@@ -92,7 +92,7 @@ enum
PID_SPLIT_HEAP = 0x0100, /* Set if the heap has been split, */
/* which means we can't fork again. */
PID_MYSELF = 0x0200, /* Flag that pid is me. */
- PID_UNUSED1 = 0x0400, /* Set if process uses Winsock. */
+ PID_NOCLDSTOP = 0x0400, /* Set if no SIGCHLD signal on stop. */
PID_INITIALIZING = 0x0800, /* Set until ready to receive signals. */
PID_USETTY = 0x1000, /* Setting this enables or disables cygwin's */
/* tty support. This is inherited by */
@@ -207,6 +207,7 @@ extern void cygwin_set_impersonation_token (const HANDLE);
extern int cygwin32_attach_handle_to_fd (char *, int, HANDLE, mode_t, DWORD);
extern int cygwin_attach_handle_to_fd (char *, int, HANDLE, mode_t, DWORD);
+#ifdef __CYGWIN__
#include <sys/resource.h>
#define TTY_CONSOLE 0x40000000
@@ -250,11 +251,10 @@ struct external_pinfo
__uid32_t uid32;
__gid32_t gid32;
};
-
+#endif /*__CYGWIN__*/
#endif /*WINVER*/
#ifdef __cplusplus
};
#endif
-
#endif /* _SYS_CYGWIN_H */
diff --git a/winsup/cygwin/libc/fnmatch.c b/winsup/cygwin/libc/fnmatch.c
new file mode 100644
index 00000000000..b48d9e00ab4
--- /dev/null
+++ b/winsup/cygwin/libc/fnmatch.c
@@ -0,0 +1,220 @@
+/* $OpenBSD: fnmatch.c,v 1.7 2000/03/23 19:13:51 millert Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94";
+#else
+static char rcsid[] = "$OpenBSD: fnmatch.c,v 1.7 2000/03/23 19:13:51 millert Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
+ * Compares a filename or pathname to a pattern.
+ */
+
+/* Just this single line added for Cygwin. */
+#include "winsup.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <fnmatch.h>
+
+#define EOS '\0'
+
+#define RANGE_MATCH 1
+#define RANGE_NOMATCH 0
+#define RANGE_ERROR (-1)
+
+static int rangematch __P((const char *, char, int, char **));
+
+int
+fnmatch(const char *pattern, const char *string, int flags)
+{
+ const char *stringstart;
+ char *newp;
+ char c, test;
+
+ for (stringstart = string;;)
+ switch (c = *pattern++) {
+ case EOS:
+ if ((flags & FNM_LEADING_DIR) && *string == '/')
+ return (0);
+ return (*string == EOS ? 0 : FNM_NOMATCH);
+ case '?':
+ if (*string == EOS)
+ return (FNM_NOMATCH);
+ if (*string == '/' && (flags & FNM_PATHNAME))
+ return (FNM_NOMATCH);
+ if (*string == '.' && (flags & FNM_PERIOD) &&
+ (string == stringstart ||
+ ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ return (FNM_NOMATCH);
+ ++string;
+ break;
+ case '*':
+ c = *pattern;
+ /* Collapse multiple stars. */
+ while (c == '*')
+ c = *++pattern;
+
+ if (*string == '.' && (flags & FNM_PERIOD) &&
+ (string == stringstart ||
+ ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ return (FNM_NOMATCH);
+
+ /* Optimize for pattern with * at end or before /. */
+ if (c == EOS) {
+ if (flags & FNM_PATHNAME)
+ return ((flags & FNM_LEADING_DIR) ||
+ strchr(string, '/') == NULL ?
+ 0 : FNM_NOMATCH);
+ else
+ return (0);
+ } else if (c == '/' && (flags & FNM_PATHNAME)) {
+ if ((string = strchr(string, '/')) == NULL)
+ return (FNM_NOMATCH);
+ break;
+ }
+
+ /* General case, use recursion. */
+ while ((test = *string) != EOS) {
+ if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
+ return (0);
+ if (test == '/' && (flags & FNM_PATHNAME))
+ break;
+ ++string;
+ }
+ return (FNM_NOMATCH);
+ case '[':
+ if (*string == EOS)
+ return (FNM_NOMATCH);
+ if (*string == '/' && (flags & FNM_PATHNAME))
+ return (FNM_NOMATCH);
+ if (*string == '.' && (flags & FNM_PERIOD) &&
+ (string == stringstart ||
+ ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ return (FNM_NOMATCH);
+
+ switch (rangematch(pattern, *string, flags, &newp)) {
+ case RANGE_ERROR:
+ /* not a good range, treat as normal text */
+ goto normal;
+ case RANGE_MATCH:
+ pattern = newp;
+ break;
+ case RANGE_NOMATCH:
+ return (FNM_NOMATCH);
+ }
+ ++string;
+ break;
+ case '\\':
+ if (!(flags & FNM_NOESCAPE)) {
+ if ((c = *pattern++) == EOS) {
+ c = '\\';
+ --pattern;
+ }
+ }
+ /* FALLTHROUGH */
+ default:
+ normal:
+ if (c != *string && !((flags & FNM_CASEFOLD) &&
+ (tolower((unsigned char)c) ==
+ tolower((unsigned char)*string))))
+ return (FNM_NOMATCH);
+ ++string;
+ break;
+ }
+ /* NOTREACHED */
+}
+
+static int
+rangematch(const char *pattern, char test, int flags, char **newp)
+{
+ int negate, ok;
+ char c, c2;
+
+ /*
+ * A bracket expression starting with an unquoted circumflex
+ * character produces unspecified results (IEEE 1003.2-1992,
+ * 3.13.2). This implementation treats it like '!', for
+ * consistency with the regular expression syntax.
+ * J.T. Conklin (conklin@ngai.kaleida.com)
+ */
+ if ((negate = (*pattern == '!' || *pattern == '^')))
+ ++pattern;
+
+ if (flags & FNM_CASEFOLD)
+ test = tolower((unsigned char)test);
+
+ /*
+ * A right bracket shall lose its special meaning and represent
+ * itself in a bracket expression if it occurs first in the list.
+ * -- POSIX.2 2.8.3.2
+ */
+ ok = 0;
+ c = *pattern++;
+ do {
+ if (c == '\\' && !(flags & FNM_NOESCAPE))
+ c = *pattern++;
+ if (c == EOS)
+ return (RANGE_ERROR);
+ if (c == '/' && (flags & FNM_PATHNAME))
+ return (RANGE_NOMATCH);
+ if ((flags & FNM_CASEFOLD))
+ c = tolower((unsigned char)c);
+ if (*pattern == '-'
+ && (c2 = *(pattern+1)) != EOS && c2 != ']') {
+ pattern += 2;
+ if (c2 == '\\' && !(flags & FNM_NOESCAPE))
+ c2 = *pattern++;
+ if (c2 == EOS)
+ return (RANGE_ERROR);
+ if (flags & FNM_CASEFOLD)
+ c2 = tolower((unsigned char)c2);
+ if (c <= test && test <= c2)
+ ok = 1;
+ } else if (c == test)
+ ok = 1;
+ } while ((c = *pattern++) != ']');
+
+ *newp = (char *)pattern;
+ return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
+}
diff --git a/winsup/cygwin/malloc.cc b/winsup/cygwin/malloc.cc
index 383a590c890..7c85bd68102 100644
--- a/winsup/cygwin/malloc.cc
+++ b/winsup/cygwin/malloc.cc
@@ -3744,6 +3744,7 @@ void fREe(mem) Void_t* mem;
mchunkptr bck; /* misc temp for linking */
mchunkptr fwd; /* misc temp for linking */
+ check_malloc_state();
/* free(0) has no effect */
if (mem != 0) {
p = mem2chunk(mem);
@@ -3878,6 +3879,7 @@ void fREe(mem) Void_t* mem;
#endif
}
}
+ check_malloc_state();
}
/*
diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc
index fea1b12498b..d9e4a7adb15 100644
--- a/winsup/cygwin/miscfuncs.cc
+++ b/winsup/cygwin/miscfuncs.cc
@@ -8,6 +8,7 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
+#define _WIN32_WINNT 0x400
#include "winsup.h"
#include "cygerrno.h"
#include <sys/errno.h>
@@ -16,6 +17,7 @@ details. */
#include <limits.h>
#include <winbase.h>
#include <winnls.h>
+#include "cygthread.h"
long tls_ix = -1;
@@ -306,13 +308,27 @@ low_priority_sleep (DWORD secs)
staylow = true;
}
- int main_prio = GetThreadPriority (hMainThread);
- if (curr_prio != main_prio)
- /* Force any threads in normal priority to be scheduled */
- SetThreadPriority (thisthread, main_prio);
- Sleep (secs);
+ if (!secs && wincap.has_switch_to_thread ())
+ {
+ for (int i = 0; i < 10; i++)
+ SwitchToThread ();
+ }
+ else
+ {
+ int new_prio;
+ if (GetCurrentThreadId () == cygthread::main_thread_id)
+ new_prio = THREAD_PRIORITY_LOWEST;
+ else
+ new_prio = GetThreadPriority (hMainThread);
+
+ if (curr_prio != new_prio)
+ /* Force any threads in normal priority to be scheduled */
+ SetThreadPriority (thisthread, new_prio);
+ Sleep (secs);
+
+ if (!staylow || curr_prio == new_prio)
+ SetThreadPriority (thisthread, curr_prio);
+ }
- if (!staylow || curr_prio == main_prio)
- SetThreadPriority (thisthread, curr_prio);
return curr_prio;
}
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
index 6c77e501540..9d7cc00fdb2 100644
--- a/winsup/cygwin/net.cc
+++ b/winsup/cygwin/net.cc
@@ -25,6 +25,7 @@ details. */
#include <netdb.h>
#define USE_SYS_TYPES_FD_SET
#include <winsock2.h>
+#include <assert.h>
#include "cygerrno.h"
#include "security.h"
#include "path.h"
@@ -381,95 +382,205 @@ set_host_errno ()
h_errno = NETDB_INTERNAL;
}
-static void
-free_char_list (char **clist)
+inline int
+DWORD_round (int n)
{
- if (clist)
- {
- for (char **cl = clist; *cl; ++cl)
- free (*cl);
- free (clist);
- }
+ return sizeof (DWORD) * (((n + sizeof (DWORD) - 1)) / sizeof (DWORD));
}
-static char **
-dup_char_list (char **src)
+inline int
+strlen_round (const char *s)
{
- char **dst;
- int cnt = 0;
-
- for (char **cl = src; *cl; ++cl)
- ++cnt;
- if (!(dst = (char **) calloc (cnt + 1, sizeof *dst)))
- return NULL;
- while (cnt-- > 0)
- if (!(dst[cnt] = strdup (src[cnt])))
- return NULL;
- return dst;
+ if (!s)
+ return 0;
+ return DWORD_round (strlen (s) + 1);
}
-#define free_addr_list(addr_list) free_char_list (addr_list)
+#pragma pack(push,2)
+struct pservent
+{
+ char *s_name;
+ char **s_aliases;
+ short s_port;
+ char *s_proto;
+};
+#pragma pack(pop)
-static char **
-dup_addr_list (char **src, unsigned int size)
+struct unionent
{
- char **dst;
- int cnt = 0;
+ char *name;
+ char **list;
+ short port_proto_addrtype;
+ short h_len;
+ union
+ {
+ char *s_proto;
+ char **h_addr_list;
+ };
+};
- for (char **cl = src; *cl; ++cl)
- ++cnt;
- if (!(dst = (char **) calloc (cnt + 1, sizeof *dst)))
- return NULL;
- while (cnt-- > 0)
- {
- if (!(dst[cnt] = (char *) malloc (size)))
- return NULL;
- memcpy (dst[cnt], src[cnt], size);
- }
- return dst;
-}
+enum struct_type
+{
+ is_hostent, is_protoent, is_servent
+};
-static void
-free_protoent_ptr (struct protoent *&p)
+static const char *entnames[] = {"host", "proto", "serv"};
+
+/* Generic "dup a {host,proto,serv}ent structure" function.
+ This is complicated because we need to be able to free the
+ structure at any point and we can't rely on the pointer contents
+ being untouched by callers. So, we allocate a chunk of memory
+ large enough to hold the structure and all of the stuff it points
+ to then we copy the source into this new block of memory.
+ The 'unionent' struct is a union of all of the currently used
+ *ent structure. */
+
+#ifdef DEBUGGING
+static void *
+#else
+static inline void *
+#endif
+dup_ent (void *old, void *src0, struct_type type)
{
- if (p)
+ if (old)
{
- debug_printf ("protoent: %s", p->p_name);
-
- if (p->p_name)
- free (p->p_name);
- free_char_list (p->p_aliases);
- free ((void *) p);
- p = NULL;
+ debug_printf ("freeing old %sent structure \"%s\" %p\n", entnames[type],
+ ((unionent *) old)->name, old);
+ free (old);
}
-}
-static struct protoent *
-dup_protoent_ptr (struct protoent *src)
-{
- if (!src)
+ if (!src0)
return NULL;
- struct protoent *dst = (struct protoent *) calloc (1, sizeof *dst);
+ unionent *src = (unionent *) src0;
+ debug_printf ("duping %sent \"%s\", %p", entnames[type],
+ src ? src->name : "<null!>", src);
- if (!dst)
- return NULL;
+ /* Find the size of the raw structure minus any character strings, etc. */
+ int sz, struct_sz;
+ switch (type)
+ {
+ case is_protoent:
+ struct_sz = sizeof (protoent);
+ break;
+ case is_servent:
+ struct_sz = sizeof (servent);
+ break;
+ case is_hostent:
+ struct_sz = sizeof (hostent);
+ break;
+ default:
+ api_fatal ("called with invalid value %d", type);
+ break;
+ }
- debug_printf ("protoent: %s", src->p_name);
+ /* Every *ent begins with a name. Calculate it's length. */
+ int namelen = strlen_round (src->name);
+ sz = struct_sz + namelen;
- dst->p_proto = src->p_proto;
- if (src->p_name && !(dst->p_name = strdup (src->p_name)))
- goto out;
- if (src->p_aliases && !(dst->p_aliases = dup_char_list (src->p_aliases)))
- goto out;
+ char **av;
+ /* The next field in every *ent is an argv list of "something".
+ Calculate the number of components and how much space the
+ character strings will take. */
+ int list_len = 0;
+ for (av = src->list; av && *av; av++)
+ {
+ list_len++;
+ sz += sizeof (char **) + strlen_round (*av);
+ }
- debug_printf ("protoent: copied %s", dst->p_name);
+ /* NULL terminate if there actually was a list */
+ if (av)
+ {
+ sz += sizeof (char **);
+ list_len++;
+ }
- return dst;
+ /* Do servent/hostent specific processing */
+ int protolen = 0;
+ int addr_list_len = 0;
+ if (type == is_servent)
+ sz += (protolen = strlen_round (src->s_proto));
+ else if (type == is_hostent)
+ {
+ /* Calculate the length and storage used for h_addr_list */
+ for (av = src->h_addr_list; av && *av; av++)
+ {
+ addr_list_len++;
+ sz += sizeof (char **) + DWORD_round (src->h_len);
+ }
+ if (av)
+ {
+ sz += sizeof (char **);
+ addr_list_len++;
+ }
+ }
-out:
- free_protoent_ptr (dst);
- return NULL;
+ /* Allocate the storage needed */
+ unionent *dst = (unionent *) calloc (1, sz);
+
+ /* Hopefully, this worked. */
+ if (dst)
+ {
+ /* This field is common to all *ent structures but named differently
+ in each, of course. */
+ dst->port_proto_addrtype = src->port_proto_addrtype;
+
+ /* Copy the name field to dst, using space just beyond the end of
+ the dst structure. */
+ char *dp = ((char *) dst) + struct_sz;
+ strcpy (dst->name = dp, src->name);
+ dp += namelen;
+
+ /* Copy the 'list' type to dst, using space beyond end of structure
+ + storage for name. */
+ if (src->list)
+ {
+ char **dav = dst->list = (char **) dp;
+ dp += sizeof (char **) * list_len;
+ for (av = src->list; av && *av; av++)
+ {
+ int len = strlen (*av) + 1;
+ memcpy (*dav++ = dp, *av, len);
+ dp += DWORD_round (len);
+ }
+ }
+
+ /* Do servent/hostent specific processing. */
+ if (type == is_servent)
+ {
+ if (src->s_proto)
+ {
+ char *s_proto;
+ /* Windows 95 idiocy. Structure is misaligned on Windows 95.
+ Kludge around this by trying a different pointer alignment. */
+ if (IsBadReadPtr (src->s_proto, sizeof (src->s_proto))
+ && !IsBadReadPtr (((pservent *) src)->s_proto, sizeof (src->s_proto)))
+ s_proto = ((pservent *) src)->s_proto;
+ else
+ s_proto = src->s_proto;
+ strcpy (dst->s_proto = dp, s_proto);
+ dp += protolen;
+ }
+ }
+ else if (type == is_hostent)
+ {
+ /* Transfer h_len and duplicate contents of h_addr_list, using
+ memory after 'list' allocation. */
+ dst->h_len = src->h_len;
+ char **dav = dst->h_addr_list = (char **) dp;
+ dp += sizeof (char **) * addr_list_len;
+ for (av = src->h_addr_list; av && *av; av++)
+ {
+ memcpy (*dav++ = dp, *av, src->h_len);
+ dp += DWORD_round (src->h_len);
+ }
+ }
+ /* Sanity check that we did our bookkeeping correctly. */
+ assert ((dp - (char *) dst) == sz);
+ }
+ debug_printf ("duped %sent \"%s\", %p", entnames[type], dst ? dst->name : "<null!>", dst);
+ return dst;
}
#ifdef _MT_SAFE
@@ -484,8 +595,8 @@ cygwin_getprotobyname (const char *p)
{
if (check_null_str_errno (p))
return NULL;
- free_protoent_ptr (protoent_buf);
- protoent_buf = dup_protoent_ptr (getprotobyname (p));
+ protoent_buf = (protoent *) dup_ent (protoent_buf, getprotobyname (p),
+ is_protoent);
if (!protoent_buf)
set_winsock_errno ();
@@ -497,8 +608,8 @@ cygwin_getprotobyname (const char *p)
extern "C" struct protoent *
cygwin_getprotobynumber (int number)
{
- free_protoent_ptr (protoent_buf);
- protoent_buf = dup_protoent_ptr (getprotobynumber (number));
+ protoent_buf = (protoent *) dup_ent (protoent_buf, getprotobynumber (number),
+ is_protoent);
if (!protoent_buf)
set_winsock_errno ();
@@ -824,71 +935,6 @@ cygwin_connect (int fd, const struct sockaddr *name, int namelen)
return res;
}
-static void
-free_servent_ptr (struct servent *&p)
-{
- if (p)
- {
- debug_printf ("servent: %s", p->s_name);
-
- if (p->s_name)
- free (p->s_name);
- if (p->s_proto)
- free (p->s_proto);
- free_char_list (p->s_aliases);
- free ((void *) p);
- p = NULL;
- }
-}
-
-#pragma pack(push,2)
-struct pservent
-{
- char *s_name;
- char **s_aliases;
- short s_port;
- char *s_proto;
-};
-
-#pragma pack(pop)
-static struct servent *
-dup_servent_ptr (struct servent *src)
-{
- if (!src)
- return NULL;
-
- struct servent *dst = (struct servent *) calloc (1, sizeof *dst);
-
- if (!dst)
- return NULL;
-
- debug_printf ("servent: %s", src->s_name);
-
- dst->s_port = src->s_port;
- if (src->s_name && !(dst->s_name = strdup (src->s_name)))
- goto out;
- if (src->s_aliases && !(dst->s_aliases = dup_char_list (src->s_aliases)))
- goto out;
- char *s_proto;
-
- if (IsBadReadPtr (src->s_proto, sizeof (src->s_proto))
- && !IsBadReadPtr (((pservent *) src)->s_proto, sizeof (src->s_proto)))
- s_proto = ((pservent *) src)->s_proto;
- else
- s_proto = src->s_proto;
-
- if (s_proto && !(dst->s_proto = strdup (s_proto)))
- goto out;
-
- debug_printf ("servent: copied %s", dst->s_name);
-
- return dst;
-
-out:
- free_servent_ptr (dst);
- return NULL;
-}
-
#ifdef _MT_SAFE
#define servent_buf _reent_winsup ()->_servent_buf
#else
@@ -905,8 +951,8 @@ cygwin_getservbyname (const char *name, const char *proto)
|| (proto != NULL && check_null_str_errno (proto)))
return NULL;
- free_servent_ptr (servent_buf);
- servent_buf = dup_servent_ptr (getservbyname (name, proto));
+ servent_buf = (servent *) dup_ent (servent_buf, getservbyname (name, proto),
+ is_servent);
if (!servent_buf)
set_winsock_errno ();
@@ -923,8 +969,8 @@ cygwin_getservbyport (int port, const char *proto)
if (proto != NULL && check_null_str_errno (proto))
return NULL;
- free_servent_ptr (servent_buf);
- servent_buf = dup_servent_ptr (getservbyport (port, proto));
+ servent_buf = (servent *) dup_ent (servent_buf, getservbyport (port, proto),
+ is_servent);
if (!servent_buf)
set_winsock_errno ();
@@ -955,54 +1001,6 @@ cygwin_gethostname (char *name, size_t len)
return 0;
}
-static void
-free_hostent_ptr (struct hostent *&p)
-{
- if (p)
- {
- debug_printf ("hostent: %s", p->h_name);
-
- if (p->h_name)
- free ((void *) p->h_name);
- free_char_list (p->h_aliases);
- free_addr_list (p->h_addr_list);
- free ((void *) p);
- p = NULL;
- }
-}
-
-static struct hostent *
-dup_hostent_ptr (struct hostent *src)
-{
- if (!src)
- return NULL;
-
- struct hostent *dst = (struct hostent *) calloc (1, sizeof *dst);
-
- if (!dst)
- return NULL;
-
- debug_printf ("hostent: %s", src->h_name);
-
- dst->h_addrtype = src->h_addrtype;
- dst->h_length = src->h_length;
- if (src->h_name && !(dst->h_name = strdup (src->h_name)))
- goto out;
- if (src->h_aliases && !(dst->h_aliases = dup_char_list (src->h_aliases)))
- goto out;
- if (src->h_addr_list
- && !(dst->h_addr_list = dup_addr_list (src->h_addr_list, src->h_length)))
- goto out;
-
- debug_printf ("hostent: copied %s", dst->h_name);
-
- return dst;
-
-out:
- free_hostent_ptr (dst);
- return NULL;
-}
-
#ifdef _MT_SAFE
#define hostent_buf _reent_winsup ()->_hostent_buf
#else
@@ -1041,8 +1039,8 @@ cygwin_gethostbyname (const char *name)
return &tmp;
}
- free_hostent_ptr (hostent_buf);
- hostent_buf = dup_hostent_ptr (gethostbyname (name));
+ hostent_buf = (hostent *) dup_ent (hostent_buf, gethostbyname (name),
+ is_hostent);
if (!hostent_buf)
{
set_winsock_errno ();
@@ -1065,8 +1063,9 @@ cygwin_gethostbyaddr (const char *addr, int len, int type)
if (__check_invalid_read_ptr_errno (addr, len))
return NULL;
- free_hostent_ptr (hostent_buf);
- hostent_buf = dup_hostent_ptr (gethostbyaddr (addr, len, type));
+ hostent_buf = (hostent *) dup_ent (hostent_buf,
+ gethostbyaddr (addr, len, type),
+ is_hostent);
if (!hostent_buf)
{
set_winsock_errno ();
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 5f078726793..ca8f207f77e 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -2360,8 +2360,7 @@ mount (const char *win32_path, const char *posix_path, unsigned flags)
{
int res = -1;
- if (check_null_empty_str_errno (win32_path)
- || check_null_empty_str_errno (posix_path))
+ if (check_null_empty_str_errno (posix_path))
/* errno set */;
else if (strpbrk (posix_path, "\\:"))
set_errno (EINVAL);
@@ -2373,7 +2372,7 @@ mount (const char *win32_path, const char *posix_path, unsigned flags)
res = mount_table->write_cygdrive_info_to_registry (posix_path, flags);
win32_path = NULL;
}
- else
+ else if (!check_null_empty_str_errno (win32_path))
res = mount_table->add_item (win32_path, posix_path, flags, TRUE);
syscall_printf ("%d = mount (%s, %s, %p)", res, win32_path, posix_path, flags);
diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h
index 3599015cc60..030c7e91b43 100644
--- a/winsup/cygwin/pinfo.h
+++ b/winsup/cygwin/pinfo.h
@@ -38,6 +38,8 @@ enum picom
PICOM_FIFO = 2
};
+extern struct sigaction *global_sigs;
+
class _pinfo
{
public:
@@ -112,11 +114,9 @@ public:
inline struct sigaction& getsig (int sig)
{
- return thread2signal ? thread2signal->sigs[sig] : sigs[sig];
+ return global_sigs[sig];
}
- inline void copysigs (_pinfo *p) {memcpy (sigs, p->sigs, sizeof (sigs));}
-
inline sigset_t& getsigmask ()
{
return thread2signal ? *thread2signal->sigmask : sig_mask;
@@ -145,7 +145,6 @@ public:
friend void __stdcall set_myself (pid_t, HANDLE);
private:
- struct sigaction sigs[NSIG];
sigset_t sig_mask; /* one set for everything to ignore. */
LONG _sigtodo[NSIG + __SIGOFFSET];
pthread *thread2signal; // NULL means thread any other means a pthread
diff --git a/winsup/cygwin/shm.cc b/winsup/cygwin/shm.cc
index 2fef656e9e4..a7edeace304 100644
--- a/winsup/cygwin/shm.cc
+++ b/winsup/cygwin/shm.cc
@@ -1,6 +1,6 @@
/* shm.cc: Single unix specification IPC interface for Cygwin.
- Copyright 2002 Red Hat, Inc.
+ Copyright 2002,2003 Red Hat, Inc.
Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
Based on code by Robert Collins <robert.collins@hotmail.com>.
diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc
index baad718b94f..2b890dd624f 100644
--- a/winsup/cygwin/signal.cc
+++ b/winsup/cygwin/signal.cc
@@ -338,6 +338,12 @@ sigaction (int sig, const struct sigaction *newact, struct sigaction *oldact)
if (newact->sa_handler == SIG_DFL && sig == SIGCHLD)
sig_clear (sig);
set_sigcatchers (oa.sa_handler, newact->sa_handler);
+ if (sig == SIGCHLD)
+ {
+ myself->process_state &= ~PID_NOCLDSTOP;
+ if (newact->sa_flags & SA_NOCLDSTOP);
+ myself->process_state |= PID_NOCLDSTOP;
+ }
}
if (oldact)
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
index f990710fa5d..6ce58fed804 100644
--- a/winsup/cygwin/sigproc.cc
+++ b/winsup/cygwin/sigproc.cc
@@ -17,6 +17,7 @@ details. */
#include <stdlib.h>
#include <sys/cygwin.h>
#include <assert.h>
+#include <sys/signal.h>
#include "cygerrno.h"
#include "sync.h"
#include "sigproc.h"
@@ -48,12 +49,35 @@ details. */
#define NZOMBIES 256
-LONG local_sigtodo[TOTSIGS];
-inline LONG* getlocal_sigtodo (int sig)
+static LONG local_sigtodo[TOTSIGS];
+struct sigaction *global_sigs;
+
+inline LONG *
+getlocal_sigtodo (int sig)
{
return local_sigtodo + __SIGOFFSET + sig;
}
+void __stdcall
+sigalloc ()
+{
+ cygheap->sigs = global_sigs =
+ (struct sigaction *) ccalloc (HEAP_SIGS, NSIG, sizeof (struct sigaction));
+}
+
+void __stdcall
+signal_fixup_after_exec ()
+{
+ global_sigs = cygheap->sigs;
+ /* Set up child's signal handlers */
+ for (int i = 0; i < NSIG; i++)
+ {
+ myself->getsig (i).sa_mask = 0;
+ if (myself->getsig (i).sa_handler != SIG_IGN)
+ myself->getsig (i).sa_handler = SIG_DFL;
+ }
+}
+
/*
* Global variables
*/
@@ -127,9 +151,9 @@ static bool NO_COPY pending_signals = false; // true if signals pending
/* Functions
*/
-static int __stdcall checkstate (waitq *);
+static int __stdcall checkstate (waitq *) __attribute__ ((regparm (1)));
static __inline__ BOOL get_proc_lock (DWORD, DWORD);
-static HANDLE __stdcall getsem (_pinfo *, const char *, int, int);
+static HANDLE __stdcall getevent (_pinfo *, const char *) __attribute__ ((regparm (2)));
static void __stdcall remove_zombie (int);
static DWORD WINAPI wait_sig (VOID *arg);
static int __stdcall stopped_or_terminated (waitq *, _pinfo *);
@@ -300,7 +324,6 @@ proc_subproc (DWORD what, DWORD val)
vchild->sid = myself->sid;
vchild->ctty = myself->ctty;
vchild->process_state |= PID_INITIALIZING | (myself->process_state & PID_USETTY);
- vchild->copysigs (myself);
sigproc_printf ("added pid %d to wait list, slot %d, winpid %p, handle %p",
vchild->pid, nchildren, vchild->dwProcessId,
@@ -540,12 +563,11 @@ sig_dispatch_pending ()
sigframe thisframe (mainthread);
- int was_pending = pending_signals;
#ifdef DEBUGGING
- sigproc_printf ("pending_signals %d", was_pending);
+ sigproc_printf ("pending_signals %d", pending_signals);
#endif
- if (!was_pending)
+ if (!pending_signals)
#ifdef DEBUGGING
sigproc_printf ("no need to wake anything up");
#else
@@ -559,10 +581,7 @@ sig_dispatch_pending ()
#endif
}
- if (was_pending)
- thisframe.call_signal_handler ();
-
- return was_pending;
+ return thisframe.call_signal_handler ();
}
/* Message initialization. Called from dll_crt0_1
@@ -679,18 +698,21 @@ sig_send (_pinfo *p, int sig, DWORD ebp, bool exception)
sigproc_printf ("pid %d, signal %d, its_me %d", p->pid, sig, its_me);
LONG *todo;
+ bool issem;
if (its_me)
{
if (!wait_for_completion)
{
thiscatch = sigcatch_nosync;
todo = myself->getsigtodo (sig);
+ issem = false;
}
else if (tid != mainthread.id)
{
thiscatch = sigcatch_nonmain;
thiscomplete = sigcomplete_nonmain;
todo = getlocal_sigtodo (sig);
+ issem = true;
}
else
{
@@ -698,12 +720,16 @@ sig_send (_pinfo *p, int sig, DWORD ebp, bool exception)
thiscomplete = sigcomplete_main;
thisframe.set (mainthread, ebp, exception);
todo = getlocal_sigtodo (sig);
+ issem = true;
}
}
- else if (thiscatch = getsem (p, "sigcatch", 0, 0))
- todo = p->getsigtodo (sig);
+ else if ((thiscatch = getevent (p, "sigcatch")))
+ {
+ todo = p->getsigtodo (sig);
+ issem = false;
+ }
else
- goto out; // Couldn't get the semaphore. getsem issued
+ goto out; // Couldn't get the semaphore. getevent issued
// an error, if appropriate.
#if WHEN_MULTI_THREAD_SIGNALS_WORK
@@ -719,15 +745,7 @@ sig_send (_pinfo *p, int sig, DWORD ebp, bool exception)
/* Notify the process that a signal has arrived.
*/
- SetLastError (0);
-
-#if 0
- int prio;
- prio = GetThreadPriority (GetCurrentThread ());
- (void) SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
-#endif
-
- if (!ReleaseSemaphore (thiscatch, 1, NULL) && (int) GetLastError () > 0)
+ if (issem ? !ReleaseSemaphore (thiscatch, 1, NULL) : !SetEvent (thiscatch))
{
/* Couldn't signal the semaphore. This probably means that the
* process is exiting.
@@ -764,24 +782,9 @@ sig_send (_pinfo *p, int sig, DWORD ebp, bool exception)
else
{
sigproc_printf ("Waiting for thiscomplete %p", thiscomplete);
-
- SetLastError (0);
rc = WaitForSingleObject (thiscomplete, WSSC);
-#if 0 // STILL NEEDED?
- /* Check for strangeness due to this thread being redirected by the
- signal handler. Sometimes a WAIT_TIMEOUT will occur when the
- thread hasn't really timed out. So, check again.
- FIXME: This isn't foolproof. */
- if (rc != WAIT_OBJECT_0 &&
- WaitForSingleObject (thiscomplete, 0) == WAIT_OBJECT_0)
- rc = WAIT_OBJECT_0;
-#endif
}
-#if 0
- SetThreadPriority (GetCurrentThread (), prio);
-#endif
-
if (rc == WAIT_OBJECT_0)
rc = 0; // Successful exit
else
@@ -892,7 +895,7 @@ out:
/* Get or create a process specific semaphore used in message passing.
*/
static HANDLE __stdcall
-getsem (_pinfo *p, const char *str, int init, int max)
+getevent (_pinfo *p, const char *str)
{
HANDLE h;
char sem_name[MAX_PATH];
@@ -912,14 +915,18 @@ getsem (_pinfo *p, const char *str, int init, int max)
low_priority_sleep (1);
}
- SetLastError (0);
if (p == NULL)
{
char sa_buf[1024];
DWORD winpid = GetCurrentProcessId ();
+#if 0
h = CreateSemaphore (sec_user_nih (sa_buf), init, max,
str = shared_name (sem_name, str, winpid));
+#else
+ h = CreateEvent (sec_user_nih (sa_buf), FALSE, FALSE,
+ str = shared_name (sem_name, str, winpid));
+#endif
p = myself;
if (!h)
{
@@ -929,8 +936,13 @@ getsem (_pinfo *p, const char *str, int init, int max)
}
else
{
+#if 0
h = OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE,
shared_name (sem_name, str, p->dwProcessId));
+#else
+ h = OpenEvent (EVENT_ALL_ACCESS, FALSE,
+ shared_name (sem_name, str, p->dwProcessId));
+#endif
if (!h)
{
@@ -1075,7 +1087,7 @@ wait_sig (VOID *self)
* sigcomplete_nonmain - semaphore signaled for non-main thread on signal
* completion
*/
- sigcatch_nosync = getsem (NULL, "sigcatch", 0, MAXLONG);
+ sigcatch_nosync = getevent (NULL, "sigcatch");
sigcatch_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
sigcatch_main = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
sigcomplete_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
@@ -1137,8 +1149,7 @@ wait_sig (VOID *self)
(void) SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY);
/* sigproc_terminate sets sig_loop_wait to zero to indicate that
- * this thread should terminate.
- */
+ this thread should terminate. */
if (rc == WAIT_TIMEOUT)
{
if (!sig_loop_wait)
@@ -1158,81 +1169,90 @@ wait_sig (VOID *self)
sigproc_printf ("awake, rc %d", rc);
LONG *todo;
if (rc != RC_NOSYNC)
- todo = *todos;
+ todo = todos[0];
else
todo = todos[1];
/* A sigcatch semaphore has been signaled. Scan the sigtodo
- * array looking for any unprocessed signals.
- */
+ array looking for any unprocessed signals. */
pending_signals = false;
- bool more_signals = false;
+ unsigned more_signals = 0;
bool saw_failed_interrupt = false;
do
- for (int sig = -__SIGOFFSET, more_signals = false; sig < NSIG; sig++)
- {
- LONG x = InterlockedDecrement (todo + sig);
- if (x < 0)
- InterlockedIncrement (todo + sig);
- else if (x >= 0)
- {
- if (sig > 0 && sig != SIGKILL && sig != SIGSTOP &&
- (sigismember (&myself->getsigmask (), sig) ||
- main_vfork->pid ||
- (sig != SIGCONT && ISSTATE (myself, PID_STOPPED))))
- {
- sigproc_printf ("signal %d blocked", sig);
- pending_signals = true; // FIXME: This will cause unnecessary sig_dispatch_pending spins
- InterlockedIncrement (myself->getsigtodo (sig));
- }
- else
- {
- /* Found a signal to process */
- if (rc != RC_NOSYNC)
- pending_signals = true; // There should be an armed semaphore, in this case
-
- sigproc_printf ("processing signal %d", sig);
- switch (sig)
- {
- case __SIGFLUSH:
- if (rc == RC_MAIN)
- {
- flush = true;
- ReleaseSemaphore (sigcatch_nosync, 1, NULL);
- goto out1;
- }
- break;
-
- /* Internal signal to turn on stracing. */
- case __SIGSTRACE:
- strace.hello ();
- break;
-
- case __SIGCOMMUNE:
- talktome ();
- break;
-
- /* A normal UNIX signal */
- default:
- sigproc_printf ("Got signal %d", sig);
- if (!sig_handle (sig))
- {
- pending_signals = saw_failed_interrupt = true;
- sigproc_printf ("couldn't send signal %d", sig);
- InterlockedIncrement (myself->getsigtodo (sig));
- }
- }
- if (rc == RC_NOSYNC)
- more_signals = x > 0;
- }
-
- if (sig == SIGCHLD)
- proc_subproc (PROC_CLEARWAIT, 0);
- if (saw_failed_interrupt || rc != RC_NOSYNC)
- goto out;
- }
- }
- while (more_signals);
+ {
+ more_signals = 0;
+ for (int sig = -__SIGOFFSET; sig < NSIG; sig++)
+ {
+ LONG x = InterlockedDecrement (todo + sig);
+ if (x < 0)
+ InterlockedIncrement (todo + sig);
+ else if (x >= 0)
+ {
+ /* If x > 0, we have to deal with a signal at some later point */
+ if (rc != RC_NOSYNC && x > 0)
+ pending_signals = true; // There should be an armed semaphore, in this case
+
+ if (sig > 0 && sig != SIGKILL && sig != SIGSTOP &&
+ (sigismember (&myself->getsigmask (), sig) ||
+ main_vfork->pid ||
+ (sig != SIGCONT && ISSTATE (myself, PID_STOPPED))))
+ {
+ sigproc_printf ("signal %d blocked", sig);
+ x = InterlockedIncrement (myself->getsigtodo (sig));
+ pending_signals = true;
+ }
+ else
+ {
+ sigproc_printf ("processing signal %d", sig);
+ switch (sig)
+ {
+ case __SIGFLUSH:
+ if (rc == RC_MAIN)
+ {
+ flush = true;
+ SetEvent (sigcatch_nosync);
+ goto out1;
+ }
+ break;
+
+ /* Internal signal to turn on stracing. */
+ case __SIGSTRACE:
+ strace.hello ();
+ break;
+
+ case __SIGCOMMUNE:
+ talktome ();
+ break;
+
+ /* A normal UNIX signal */
+ default:
+ sigproc_printf ("Got signal %d", sig);
+ if (!sig_handle (sig))
+ {
+ saw_failed_interrupt = true;
+ x = InterlockedIncrement (myself->getsigtodo (sig));
+ pending_signals = true;
+ }
+ }
+ if (rc == RC_NOSYNC && x > 0)
+ more_signals++;
+ }
+
+ if (sig == SIGCHLD)
+ proc_subproc (PROC_CLEARWAIT, 0);
+
+ /* Need to take special action if an interrupt failed due to main thread not
+ getting around to calling handler yet. */
+ if (saw_failed_interrupt || rc != RC_NOSYNC)
+ goto out;
+ }
+ }
+#ifdef DEBUGGING
+ if (more_signals > 100)
+ system_printf ("hmm. infinite loop? more_signals %u\n", more_signals);
+#endif
+ }
+ while (more_signals && sig_loop_wait);
out:
/* Signal completion of signal handling depending on which semaphore
@@ -1245,10 +1265,11 @@ wait_sig (VOID *self)
sigproc_printf ("set main thread completion event");
flush = false;
}
+
out1:
if (saw_failed_interrupt)
{
- ReleaseSemaphore (sigcatch_nosync, 1, NULL);
+ SetEvent (sigcatch_nosync);
low_priority_sleep (0); /* Hopefully, other thread will be waking up soon. */
}
sigproc_printf ("looping");
diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h
index d3061bc504c..360ae8bcba3 100644
--- a/winsup/cygwin/sigproc.h
+++ b/winsup/cygwin/sigproc.h
@@ -101,12 +101,12 @@ BOOL __stdcall my_parent_is_alive ();
extern "C" int __stdcall sig_dispatch_pending ();
extern "C" void __stdcall set_process_mask (sigset_t newmask);
extern "C" void __stdcall reset_signal_arrived ();
-int __stdcall sig_handle (int);
-void __stdcall sig_clear (int);
-void __stdcall sig_set_pending (int);
+int __stdcall sig_handle (int) __attribute__ ((regparm (1)));
+void __stdcall sig_clear (int) __attribute__ ((regparm (1)));
+void __stdcall sig_set_pending (int) __attribute__ ((regparm (1)));
int __stdcall handle_sigsuspend (sigset_t);
-int __stdcall proc_subproc (DWORD, DWORD);
+int __stdcall proc_subproc (DWORD, DWORD) __attribute__ ((regparm (2)));
class _pinfo;
void __stdcall proc_terminate ();
@@ -120,6 +120,7 @@ int __stdcall sig_send (_pinfo *, int, DWORD ebp = (DWORD) __builtin_frame_addre
void __stdcall signal_fixup_after_fork ();
void __stdcall signal_fixup_after_exec ();
void __stdcall wait_for_sigthread ();
+void __stdcall sigalloc ();
extern char myself_nowait_dummy[];
extern char myself_nowait_nonmain_dummy[];
diff --git a/winsup/cygwin/speclib b/winsup/cygwin/speclib
index cd463f808ae..9de9f50c4c8 100755
--- a/winsup/cygwin/speclib
+++ b/winsup/cygwin/speclib
@@ -26,7 +26,7 @@ sort -o /tmp/$$.objs -u /tmp/$$.objs
[ -s /tmp/$$.objs ] || { echo "speclib: couldn't find symbols for $lib" 1>&2; exit 1; }
-/bin/rm -f /tmp/$$>dir
+/bin/rm -rf /tmp/$$.dir
mkdir /tmp/$$.dir
cd /tmp/$$.dir
if v; then
diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc
index dbc39132d59..33676ee6f31 100644
--- a/winsup/cygwin/wincap.cc
+++ b/winsup/cygwin/wincap.cc
@@ -49,7 +49,8 @@ static NO_COPY wincaps wincap_unknown = {
supports_reading_modem_output_lines:false,
needs_memory_protection:false,
pty_needs_alloc_console:false,
- has_terminal_services:false
+ has_terminal_services:false,
+ has_switch_to_thread:false
};
static NO_COPY wincaps wincap_95 = {
@@ -90,7 +91,8 @@ static NO_COPY wincaps wincap_95 = {
supports_reading_modem_output_lines:false,
needs_memory_protection:false,
pty_needs_alloc_console:false,
- has_terminal_services:false
+ has_terminal_services:false,
+ has_switch_to_thread:false
};
static NO_COPY wincaps wincap_95osr2 = {
@@ -131,7 +133,8 @@ static NO_COPY wincaps wincap_95osr2 = {
supports_reading_modem_output_lines:false,
needs_memory_protection:false,
pty_needs_alloc_console:false,
- has_terminal_services:false
+ has_terminal_services:false,
+ has_switch_to_thread:false
};
static NO_COPY wincaps wincap_98 = {
@@ -172,7 +175,8 @@ static NO_COPY wincaps wincap_98 = {
supports_reading_modem_output_lines:false,
needs_memory_protection:false,
pty_needs_alloc_console:false,
- has_terminal_services:false
+ has_terminal_services:false,
+ has_switch_to_thread:false
};
static NO_COPY wincaps wincap_98se = {
@@ -213,7 +217,8 @@ static NO_COPY wincaps wincap_98se = {
supports_reading_modem_output_lines:false,
needs_memory_protection:false,
pty_needs_alloc_console:false,
- has_terminal_services:false
+ has_terminal_services:false,
+ has_switch_to_thread:false
};
static NO_COPY wincaps wincap_me = {
@@ -254,7 +259,8 @@ static NO_COPY wincaps wincap_me = {
supports_reading_modem_output_lines:false,
needs_memory_protection:false,
pty_needs_alloc_console:false,
- has_terminal_services:false
+ has_terminal_services:false,
+ has_switch_to_thread:false
};
static NO_COPY wincaps wincap_nt3 = {
@@ -295,7 +301,8 @@ static NO_COPY wincaps wincap_nt3 = {
supports_reading_modem_output_lines:true,
needs_memory_protection:true,
pty_needs_alloc_console:true,
- has_terminal_services:false
+ has_terminal_services:false,
+ has_switch_to_thread:false
};
static NO_COPY wincaps wincap_nt4 = {
@@ -336,7 +343,8 @@ static NO_COPY wincaps wincap_nt4 = {
supports_reading_modem_output_lines:true,
needs_memory_protection:true,
pty_needs_alloc_console:true,
- has_terminal_services:false
+ has_terminal_services:false,
+ has_switch_to_thread:true
};
static NO_COPY wincaps wincap_nt4sp4 = {
@@ -377,7 +385,8 @@ static NO_COPY wincaps wincap_nt4sp4 = {
supports_reading_modem_output_lines:true,
needs_memory_protection:true,
pty_needs_alloc_console:true,
- has_terminal_services:false
+ has_terminal_services:false,
+ has_switch_to_thread:true
};
static NO_COPY wincaps wincap_2000 = {
@@ -418,7 +427,8 @@ static NO_COPY wincaps wincap_2000 = {
supports_reading_modem_output_lines:true,
needs_memory_protection:true,
pty_needs_alloc_console:true,
- has_terminal_services:true
+ has_terminal_services:true,
+ has_switch_to_thread:true
};
static NO_COPY wincaps wincap_xp = {
@@ -459,7 +469,8 @@ static NO_COPY wincaps wincap_xp = {
supports_reading_modem_output_lines:true,
needs_memory_protection:true,
pty_needs_alloc_console:true,
- has_terminal_services:true
+ has_terminal_services:true,
+ has_switch_to_thread:true
};
static NO_COPY wincaps wincap_2003 = {
@@ -500,7 +511,8 @@ static NO_COPY wincaps wincap_2003 = {
supports_reading_modem_output_lines:true,
needs_memory_protection:true,
pty_needs_alloc_console:true,
- has_terminal_services:true
+ has_terminal_services:true,
+ has_switch_to_thread:true
};
wincapc wincap;
diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h
index b1f43d6ef57..faf2469063a 100644
--- a/winsup/cygwin/wincap.h
+++ b/winsup/cygwin/wincap.h
@@ -51,6 +51,7 @@ struct wincaps
unsigned needs_memory_protection : 1;
unsigned pty_needs_alloc_console : 1;
unsigned has_terminal_services : 1;
+ unsigned has_switch_to_thread : 1;
};
class wincapc
@@ -106,6 +107,7 @@ public:
bool IMPLEMENT (needs_memory_protection)
bool IMPLEMENT (pty_needs_alloc_console)
bool IMPLEMENT (has_terminal_services)
+ bool IMPLEMENT (has_switch_to_thread)
#undef IMPLEMENT
};