summaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
authorRobin Watts <Robin.Watts@artifex.com>2021-10-27 17:54:20 +0100
committerRobin Watts <Robin.Watts@artifex.com>2021-11-05 14:32:19 +0000
commit91e29d42a601689f13e9202fc6b582d53901fbc2 (patch)
tree7a8526c18f050af408749cc587a49a0ca13b1474 /base
parent6dd05a013f66a9322f92f62fd2d46be9bfa82097 (diff)
downloadghostpdl-91e29d42a601689f13e9202fc6b582d53901fbc2.tar.gz
Runtime safety of non threadsafe devices and rework globals.
Some devices within Ghostscript (currently the x11 devices, uniprint and opvp/oprp) use non const static variables, so cannot be run in multiple instances at a time. We now maintain a core "count" of how many non-threadsafe devices are being used at any time. This value can be atomically adjusted by calls to gs_lib_ctx_nts_adjust. Non threadsafe devices now call gx_init_non_threadsafe_device either as or as part of their initialise_device proc. This function attempts to increment the non-threadsafe count and fails to init if there is already a non-threadsafe device running. On success, the device finalize method is modified so that it will decrement the count at the end. The known non-threadsafe devices are updated to call this. In order to have somewhere safe to store this count, we introduce a gs_globals structure, shared between instances. Setting this up without race conditions requires some new gp_ functions that can make use of platform specific threading primitives. We have these implemented for both windows and pthread based platforms. On other platforms, we drop back to the old unsafe mechanism for counting instances. While we do this work, we take the opportunity to push the gs_memory_t pointer used for non-threadsafe debug printing into thread local storage. This enables us to remove the remaining GS_THREADSAFE guarded compilation from the source code. What is left is broadly down to allowing debugging collection for statistics, and these are now controlled by specific COLLECT_STATS_XXX defines. It is assumed that anyone wanting to collect such stats is smart enough to not try to do so while using Ghostscript in a multi-instance environment.
Diffstat (limited to 'base')
-rw-r--r--base/gdebug.h4
-rw-r--r--base/gdevm24.c8
-rw-r--r--base/gdevm40.c8
-rw-r--r--base/gdevm48.c8
-rw-r--r--base/gdevm56.c8
-rw-r--r--base/gdevm64.c8
-rw-r--r--base/globals.h41
-rw-r--r--base/gp.h15
-rw-r--r--base/gp_mspol.c5
-rw-r--r--base/gp_nsync.c25
-rw-r--r--base/gp_psync.c73
-rw-r--r--base/gp_wsync.c137
-rw-r--r--base/gscoord.c2
-rw-r--r--base/gsdevice.c22
-rw-r--r--base/gserrors.h107
-rw-r--r--base/gsfcmap1.c37
-rw-r--r--base/gshsb.c2
-rw-r--r--base/gsht.c2
-rw-r--r--base/gshtscr.c2
-rw-r--r--base/gslibctx.c78
-rw-r--r--base/gslibctx.h13
-rw-r--r--base/gsmalloc.c3
-rw-r--r--base/gsmisc.c40
-rw-r--r--base/gxblend.c4
-rw-r--r--base/gxcldev.h4
-rw-r--r--base/gxclip.c6
-rw-r--r--base/gxclpath.c2
-rw-r--r--base/gxclutil.c6
-rw-r--r--base/gxdevice.h3
-rw-r--r--base/gxfill.c4
-rw-r--r--base/gxfill.h4
-rw-r--r--base/gxifast.c6
-rw-r--r--base/gxpflat.c10
-rw-r--r--base/gxstroke.c8
-rw-r--r--base/lib.mak20
-rw-r--r--base/mkromfs.c21
-rw-r--r--base/scfe.c13
-rw-r--r--base/shc.h2
-rw-r--r--base/std.h146
-rw-r--r--base/ttinterp.c16
-rw-r--r--base/winplat.mak2
41 files changed, 512 insertions, 413 deletions
diff --git a/base/gdebug.h b/base/gdebug.h
index 8d6633310..6e57b774e 100644
--- a/base/gdebug.h
+++ b/base/gdebug.h
@@ -94,7 +94,7 @@ bool gs_debug_c(int /*char */ );
extern gp_file *gs_debug_out;
/* Debugging printout macros. */
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#if defined(DEBUG)
# define if_debug0(c,s)\
BEGIN if (gs_debug_c(c)) dlprintf(s); END
# define if_debug1(c,s,a1)\
@@ -272,9 +272,7 @@ void debug_dump_bytes(const gs_memory_t *mem,
void debug_dump_bitmap(const gs_memory_t *mem,
const byte * from, uint raster, uint height,
const char *msg);
-#ifndef GS_THREADSAFE
void debug_print_string_hex_nomem(const byte * str, uint len);
-#endif
void debug_print_string_hex(const gs_memory_t *mem, const byte * str, uint len);
#endif /* gdebug_INCLUDED */
diff --git a/base/gdevm24.c b/base/gdevm24.c
index 913f00284..3683bd956 100644
--- a/base/gdevm24.c
+++ b/base/gdevm24.c
@@ -33,7 +33,9 @@
/*#define USE_MEMCPY*/
/* Define debugging statistics. */
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+/* #define COLLECT_STATS_MEM24 */
+
+#ifdef COLLECT_STATS_MEM24
struct stats_mem24_s {
long
fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
@@ -124,7 +126,7 @@ mem_true24_fill_rectangle(gx_device * dev,
*/
fit_fill_xywh(dev, x, y, w, h);
INCR(fill);
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_MEM24
stats_mem24.ftotal += w;
#endif
if (w >= 5) {
@@ -206,7 +208,7 @@ mem_true24_fill_rectangle(gx_device * dev,
INCR(fsetc);
set_color24_cache(color, r, g, b);
}
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_MEM24
{
int ci;
for (ci = 0; ci < prev_count; ++ci)
diff --git a/base/gdevm40.c b/base/gdevm40.c
index 31425f1a6..18a0aaf29 100644
--- a/base/gdevm40.c
+++ b/base/gdevm40.c
@@ -21,7 +21,9 @@
#include "gdevmem.h" /* private definitions */
/* Define debugging statistics. */
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+/* #define COLLECT_STATS_MEM40 */
+
+#ifdef COLLECT_STATS_MEM40
struct stats_mem40_s {
long
fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
@@ -116,7 +118,7 @@ mem_true40_fill_rectangle(gx_device * dev,
*/
fit_fill_xywh(dev, x, y, w, h);
INCR(fill);
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_MEM40
stats_mem40.ftotal += w;
#endif
if (w >= 5) {
@@ -146,7 +148,7 @@ mem_true40_fill_rectangle(gx_device * dev,
INCR(fsetc);
set_color40_cache(color, a, b, c, d, e);
}
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_MEM40
{
int ci;
for (ci = 0; ci < prev_count; ++ci)
diff --git a/base/gdevm48.c b/base/gdevm48.c
index 0a3d8a29c..4782495ec 100644
--- a/base/gdevm48.c
+++ b/base/gdevm48.c
@@ -21,7 +21,9 @@
#include "gdevmem.h" /* private definitions */
/* Define debugging statistics. */
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+/* #define COLLECT_STATS_MEM48 */
+
+#ifdef COLLECT_STATS_MEM48
struct stats_mem48_s {
long
fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
@@ -113,7 +115,7 @@ mem_true48_fill_rectangle(gx_device * dev,
*/
fit_fill_xywh(dev, x, y, w, h);
INCR(fill);
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_MEM48
stats_mem48.ftotal += w;
#endif
if (w >= 5) {
@@ -141,7 +143,7 @@ mem_true48_fill_rectangle(gx_device * dev,
INCR(fsetc);
set_color48_cache(color, a, b, c, d, e, f);
}
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_MEM48
{
int ci;
for (ci = 0; ci < prev_count; ++ci)
diff --git a/base/gdevm56.c b/base/gdevm56.c
index 70cfd942e..624c16899 100644
--- a/base/gdevm56.c
+++ b/base/gdevm56.c
@@ -21,7 +21,9 @@
#include "gdevmem.h" /* private definitions */
/* Define debugging statistics. */
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+/* #define COLLECT_STATS_MEM56 */
+
+#ifdef COLLECT_STATS_MEM56
struct stats_mem56_s {
long
fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
@@ -123,7 +125,7 @@ mem_true56_fill_rectangle(gx_device * dev,
*/
fit_fill_xywh(dev, x, y, w, h);
INCR(fill);
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_MEM56
stats_mem56.ftotal += w;
#endif
if (w >= 5) {
@@ -155,7 +157,7 @@ mem_true56_fill_rectangle(gx_device * dev,
INCR(fsetc);
set_color56_cache(color, a, b, c, d, e, f, g);
}
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_MEM56
{
int ci;
for (ci = 0; ci < prev_count; ++ci)
diff --git a/base/gdevm64.c b/base/gdevm64.c
index a66c3c165..64e174afd 100644
--- a/base/gdevm64.c
+++ b/base/gdevm64.c
@@ -21,7 +21,9 @@
#include "gdevmem.h" /* private definitions */
/* Define debugging statistics. */
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+/* #define COLLECT_STATS_MEM64 */
+
+#ifdef COLLECT_STATS_MEM64
struct stats_mem64_s {
long
fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
@@ -104,7 +106,7 @@ mem_true64_fill_rectangle(gx_device * dev,
*/
fit_fill_xywh(dev, x, y, w, h);
INCR(fill);
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_MEM64
stats_mem64.ftotal += w;
#endif
if (h <= 0)
@@ -112,7 +114,7 @@ mem_true64_fill_rectangle(gx_device * dev,
if (w >= 5) {
INCR(fwide);
setup_rect(dest);
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_MEM64
{
int ci;
for (ci = 0; ci < prev_count; ++ci)
diff --git a/base/globals.h b/base/globals.h
new file mode 100644
index 000000000..d232d2041
--- /dev/null
+++ b/base/globals.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2001-2021 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+
+/* This routine abstracts the platform specific ways to get some
+ * global state shared between different instances of the gs libary.
+ * There is special effort required to ensure that multiple instances
+ * do not have race conditions in the setup of such global state. Not
+ * all platforms support this, so on such platforms, no global state
+ * is supported. */
+#include "std.h"
+#include "gslibctx.h"
+
+/* Interface to platform-specific global variable routines. */
+
+#ifndef gs_globals_INCLUDED
+# define gs_globals_INCLUDED
+
+struct gs_globals
+{
+ int non_threadsafe_count;
+};
+
+void gs_globals_init(gs_globals *globals);
+
+void gp_global_lock(gs_globals *globals);
+void gp_global_unlock(gs_globals *globals);
+
+#endif /* gs_globals_INCLUDED */
diff --git a/base/gp.h b/base/gp.h
index b58206b5f..33a35cccc 100644
--- a/base/gp.h
+++ b/base/gp.h
@@ -23,6 +23,8 @@
#include "stat_.h"
#include "gstypes.h"
#include "gscdefs.h" /* for gs_serialnumber */
+#include "globals.h"
+
/*
* This file defines the interface to ***ALL*** platform-specific routines,
* with the exception of the thread/synchronization interface (gpsync.h)
@@ -704,4 +706,17 @@ gp_validate_path(const gs_memory_t *mem,
const char *path,
const char *mode);
+/*
+ * Fetch a pointer to the globals structure. This is cleverly synchronised
+ * so that the first call to this function is guaranteed to return a safely
+ * (and atomically) initialised structure.
+ *
+ * Platforms that can't perform this synchronisation just return NULL.
+ */
+struct gs_globals *gp_get_globals(void);
+
+void gp_set_debug_mem_ptr(gs_memory_t *mem);
+
+gs_memory_t *gp_get_debug_mem_ptr(void);
+
#endif /* gp_INCLUDED */
diff --git a/base/gp_mspol.c b/base/gp_mspol.c
index 560fb3fee..88d831718 100644
--- a/base/gp_mspol.c
+++ b/base/gp_mspol.c
@@ -32,10 +32,9 @@
int
gp_check_interrupts(const gs_memory_t *mem)
{
-#ifndef GS_THREADSAFE
+#ifdef DEBUG
if(mem == NULL) {
- /* MAJOR HACK will NOT work in multithreaded environment */
- mem = gs_lib_ctx_get_non_gc_memory_t();
+ mem = gp_get_debug_mem_ptr();
}
#endif
if (mem && mem->gs_lib_ctx && mem->gs_lib_ctx->core->poll_fn)
diff --git a/base/gp_nsync.c b/base/gp_nsync.c
index cb16fa309..8eb66dc62 100644
--- a/base/gp_nsync.c
+++ b/base/gp_nsync.c
@@ -18,6 +18,8 @@
#include "std.h"
#include "gserrors.h"
#include "gpsync.h"
+#include "gp.h"
+#include "globals.h"
/* ------- Synchronization primitives -------- */
@@ -118,3 +120,26 @@ void
gp_thread_finish(gp_thread_id thread)
{
}
+
+/* No threading -> no globals */
+gs_globals *gp_get_globals(void)
+{
+ return NULL;
+}
+
+void gp_global_lock(gs_globals *globals)
+{
+}
+
+void gp_global_unlock(gs_globals *globals)
+{
+}
+
+void gp_set_debug_mem_ptr(gs_memory_t *mem)
+{
+}
+
+gs_memory_t *gp_get_debug_mem_ptr(void)
+{
+ return NULL;
+}
diff --git a/base/gp_psync.c b/base/gp_psync.c
index 7fc177fa8..a158d1718 100644
--- a/base/gp_psync.c
+++ b/base/gp_psync.c
@@ -23,6 +23,8 @@
#include "gserrors.h"
#include "gpsync.h"
#include "assert_.h"
+#include "gp.h"
+#include "globals.h"
/*
* Thanks to Larry Jones <larry.jones@sdrc.com> for this revision of
* Aladdin's original code into a form that depends only on POSIX APIs.
@@ -37,6 +39,65 @@
# define PTHREAD_CREATE_DETACHED 1
#endif
+static struct
+{
+ pthread_once_t once;
+ pthread_mutex_t mutex;
+ gs_globals globals;
+#ifdef DEBUG
+ pthread_key_t tlsKey;
+#endif
+} GhostscriptGlobals = { PTHREAD_ONCE_INIT, PTHREAD_MUTEX_INITIALIZER };
+
+static void init_globals(void)
+{
+ if (pthread_mutex_init(&GhostscriptGlobals.mutex, NULL))
+ exit(1);
+#ifdef DEBUG
+ if (pthread_key_create(&GhostscriptGlobals.tlsKey, NULL))
+ exit(1);
+#endif
+ gs_globals_init(&GhostscriptGlobals.globals);
+}
+
+gs_globals *gp_get_globals(void)
+{
+ if (pthread_once(&GhostscriptGlobals.once, init_globals))
+ return NULL;
+
+ return &GhostscriptGlobals.globals;
+}
+
+void gp_global_lock(gs_globals *globals)
+{
+ if (globals == NULL)
+ return;
+ pthread_mutex_lock(&GhostscriptGlobals.mutex);
+}
+
+void gp_global_unlock(gs_globals *globals)
+{
+ if (globals == NULL)
+ return;
+ pthread_mutex_unlock(&GhostscriptGlobals.mutex);
+}
+
+void gp_set_debug_mem_ptr(gs_memory_t *mem)
+{
+#ifdef DEBUG
+ pthread_setspecific(GhostscriptGlobals.tlsKey, mem);
+#endif
+}
+
+gs_memory_t *gp_get_debug_mem_ptr(void)
+{
+#ifdef DEBUG
+ return (gs_memory_t *)pthread_getspecific(GhostscriptGlobals.tlsKey);
+#else
+ return NULL;
+#endif
+}
+
/* ------- Synchronization primitives -------- */
/* Semaphore supports wait/signal semantics */
@@ -320,6 +381,9 @@ gp_monitor_leave(gp_monitor * mona)
typedef struct gp_thread_creation_closure_s {
gp_thread_creation_callback_t proc; /* actual start procedure */
void *proc_data; /* closure data for proc */
+#ifdef DEBUG
+ gs_memory_t *mem;
+#endif
} gp_thread_creation_closure_t;
/* Wrapper procedure called to start the new thread. */
@@ -330,6 +394,9 @@ gp_thread_begin_wrapper(void *thread_data /* gp_thread_creation_closure_t * */)
closure = *(gp_thread_creation_closure_t *)thread_data;
free(thread_data);
+#ifdef DEBUG
+ pthread_setspecific(GhostscriptGlobals.tlsKey, closure.mem);
+#endif
DISCARD(closure.proc(closure.proc_data));
return NULL; /* return value is ignored */
}
@@ -355,6 +422,9 @@ gp_create_thread(gp_thread_creation_callback_t proc, void *proc_data)
return_error(gs_error_VMerror);
closure->proc = proc;
closure->proc_data = proc_data;
+#ifdef DEBUG
+ closure->mem = pthread_getspecific(GhostscriptGlobals.tlsKey);
+#endif
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
code = pthread_create(&ignore_thread, &attr, gp_thread_begin_wrapper,
@@ -380,6 +450,9 @@ gp_thread_start(gp_thread_creation_callback_t proc, void *proc_data,
return_error(gs_error_VMerror);
closure->proc = proc;
closure->proc_data = proc_data;
+#ifdef DEBUG
+ closure->mem = pthread_getspecific(GhostscriptGlobals.tlsKey);
+#endif
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
code = pthread_create(&new_thread, &attr, gp_thread_begin_wrapper,
diff --git a/base/gp_wsync.c b/base/gp_wsync.c
index 36ec04393..89b299d42 100644
--- a/base/gp_wsync.c
+++ b/base/gp_wsync.c
@@ -20,8 +20,128 @@
#include "malloc_.h"
#include "gserrors.h"
#include "gpsync.h"
+#include "gp.h"
+#include "globals.h"
#include <process.h>
+/* We have 2 possible implementations of the routines to initialise
+ * globals. One uses the InitOnceExecuteOnce facility present in
+ * windows versions >= Vista, the other uses a mutex and
+ * InterlockedCompareExchangePointer and works on versions >=
+ * XP. Accordingly, we use the XP-capable version. The other version
+ * is retained for reference. */
+#define XP_COMPATIBLE_INIT
+
+/* Whatever happens, if we are compiling for a version < Vista
+ * we MUST use the XP version. */
+#if _WIN32_WINNT < 0x600
+#ifndef XP_COMPATIBLE_INIT
+#define XP_COMPATIBLE_INIT
+#endif
+#endif
+
+static struct
+{
+#ifdef XP_COMPATIBLE_INIT
+ HANDLE once_mutex;
+ int inited;
+#else
+ INIT_ONCE once;
+#endif
+ CRITICAL_SECTION lock;
+ gs_globals globals;
+#ifdef DEBUG
+ DWORD tlsIndex;
+#endif
+} GhostscriptGlobals = { INIT_ONCE_STATIC_INIT };
+
+static BOOL CALLBACK init_globals(PINIT_ONCE InitOnce,
+ PVOID Parameter,
+ PVOID *lpContext)
+{
+#ifdef METRO
+ InitializeCriticalSectionEx(&GhostscriptGlobals.lock, 0, 0); /* returns no status */
+#else
+ InitializeCriticalSection(&GhostscriptGlobals.lock); /* returns no status */
+#endif
+#ifdef DEBUG
+ GhostscriptGlobals.tlsIndex = TlsAlloc();
+#endif
+ gs_globals_init(&GhostscriptGlobals.globals);
+ return TRUE;
+}
+
+gs_globals *gp_get_globals(void)
+{
+ PVOID lpContext;
+#ifdef XP_COMPATIBLE_INIT
+ /* Prior to Windows Vista, we don't have InitOnceExecuteOnce
+ * capability, so we have to fudge it. Windows XP provides
+ * InterlockedCompareExchangePointer, so we can use that.
+ * We don't care about anything earlier than XP. */
+
+ /* If we haven't got a mutex yet...*/
+ if (GhostscriptGlobals.once_mutex == NULL) {
+ /* Make one */
+ HANDLE p = CreateMutex(NULL, FALSE, NULL);
+ /* Now atomically swap that one into the structure. */
+ if (InterlockedCompareExchangePointer((PVOID *)&GhostscriptGlobals.once_mutex, (PVOID)p, NULL) != NULL) {
+ /* If there was one there already, ditch ours and just use the one that was there already. */
+ CloseHandle(p);
+ }
+ }
+ WaitForSingleObject(GhostscriptGlobals.once_mutex, INFINITE);
+ if (GhostscriptGlobals.inited == 0) {
+ init_globals(NULL, NULL, &lpContext);
+ GhostscriptGlobals.inited = 1;
+ }
+ ReleaseMutex(GhostscriptGlobals.once_mutex);
+#else
+ BOOL status = InitOnceExecuteOnce(&GhostscriptGlobals.once,
+ init_globals,
+ NULL,
+ &lpContext);
+ if (status == FALSE)
+ return NULL;
+#endif
+
+ return &GhostscriptGlobals.globals;
+}
+
+
+void gp_global_lock(gs_globals *globals)
+{
+ if (globals == NULL)
+ return;
+ EnterCriticalSection(&GhostscriptGlobals.lock);
+}
+
+void gp_global_unlock(gs_globals *globals)
+{
+ if (globals == NULL)
+ return;
+ LeaveCriticalSection(&GhostscriptGlobals.lock);
+}
+
+void gp_set_debug_mem_ptr(gs_memory_t *mem)
+{
+#ifdef DEBUG
+ if (GhostscriptGlobals.tlsIndex != TLS_OUT_OF_INDEXES)
+ TlsSetValue(GhostscriptGlobals.tlsIndex, mem);
+#endif
+}
+
+gs_memory_t *gp_get_debug_mem_ptr(void)
+{
+#ifdef DEBUG
+ if (GhostscriptGlobals.tlsIndex == TLS_OUT_OF_INDEXES)
+ return NULL;
+ return (gs_memory_t *)TlsGetValue(GhostscriptGlobals.tlsIndex);
+#else
+ return NULL;
+#endif
+}
+
/* It seems that both Borland and Watcom *should* be able to cope with the
* new style threading using _beginthreadex/_endthreadex. I am unable to test
* this properly however, and the tests I have done lead me to believe it
@@ -187,6 +307,7 @@ gp_monitor_leave(
typedef struct gp_thread_creation_closure_s {
gp_thread_creation_callback_t function; /* function to start */
void *data; /* magic data to pass to thread */
+ gs_memory_t *mem;
} gp_thread_creation_closure;
/* Origin of new threads started by gp_create_thread */
@@ -199,6 +320,10 @@ gp_thread_begin_wrapper(
closure = *(gp_thread_creation_closure *)thread_data;
free(thread_data);
+#ifdef DEBUG
+ if (GhostscriptGlobals.tlsIndex != TLS_OUT_OF_INDEXES)
+ TlsSetValue(GhostscriptGlobals.tlsIndex, closure.mem);
+#endif
(*closure.function)(closure.data);
_endthread();
}
@@ -218,6 +343,10 @@ gp_create_thread(
return_error(gs_error_VMerror);
closure->function = function;
closure->data = data;
+#ifdef DEBUG
+ if (GhostscriptGlobals.tlsIndex != TLS_OUT_OF_INDEXES)
+ closure->mem = TlsGetValue(GhostscriptGlobals.tlsIndex);
+#endif
/*
* Start thread_wrapper. The Watcom _beginthread returns (int)(-1) if
@@ -246,6 +375,10 @@ gp_thread_start_wrapper(void *thread_data)
closure = *(gp_thread_creation_closure *)thread_data;
free(thread_data);
+#ifdef DEBUG
+ if (GhostscriptGlobals.tlsIndex != TLS_OUT_OF_INDEXES)
+ TlsSetValue(GhostscriptGlobals.tlsIndex, closure.mem);
+#endif
(*closure.function)(closure.data);
_endthreadex(0);
return 0;
@@ -268,6 +401,10 @@ int gp_thread_start(gp_thread_creation_callback_t function,
return_error(gs_error_VMerror);
closure->function = function;
closure->data = data;
+#ifdef DEBUG
+ if (GhostscriptGlobals.tlsIndex != TLS_OUT_OF_INDEXES)
+ closure->mem = TlsGetValue(GhostscriptGlobals.tlsIndex);
+#endif
hThread = (HANDLE)_beginthreadex(NULL, 0, &gp_thread_start_wrapper,
closure, 0, &threadID);
if (hThread == (HANDLE)0)
diff --git a/base/gscoord.c b/base/gscoord.c
index f32e4cd3e..8134980ee 100644
--- a/base/gscoord.c
+++ b/base/gscoord.c
@@ -618,7 +618,6 @@ gx_matrix_to_fixed_coeff(const gs_matrix * pmat, register fixed_coeff * pfc,
SET_C(yx);
SET_C(yy);
#undef SET_C
-#ifndef GS_THREADSAFE
#ifdef DEBUG
if (gs_debug_c('x')) {
dlprintf6("[x]ctm: [%6g %6g %6g %6g %6g %6g]\n",
@@ -628,7 +627,6 @@ gx_matrix_to_fixed_coeff(const gs_matrix * pmat, register fixed_coeff * pfc,
pfc->shift);
}
#endif
-#endif
pfc->max_bits = max_bits;
return 0;
}
diff --git a/base/gsdevice.c b/base/gsdevice.c
index b02c324ca..b0be4f82c 100644
--- a/base/gsdevice.c
+++ b/base/gsdevice.c
@@ -1435,3 +1435,25 @@ gdev_space_params_cmp(const gdev_space_params sp1,
return(0);
}
+
+static void
+release_nts_lock(gx_device *dev)
+{
+ (void)gs_lib_ctx_nts_adjust(dev->memory, -1);
+}
+
+int gx_init_non_threadsafe_device(gx_device *dev)
+{
+ int code;
+
+ if (dev == NULL || dev->finalize != NULL)
+ return gs_error_unknownerror;
+
+ code = gs_lib_ctx_nts_adjust(dev->memory, 1);
+ if (code < 0)
+ return code;
+
+ dev->finalize = release_nts_lock;
+
+ return 0;
+}
diff --git a/base/gserrors.h b/base/gserrors.h
index 91b05cdf7..0e4982d79 100644
--- a/base/gserrors.h
+++ b/base/gserrors.h
@@ -129,16 +129,11 @@ enum gs_error_type {
typedef enum gs_error_type gs_error_t;
int gs_log_error(int, const char *, int);
-#if !defined(DEBUG) || defined(GS_THREADSAFE)
+#if !defined(DEBUG)
# define gs_log_error(err, file, line) (err)
#endif
-#ifdef GS_THREADSAFE
-#define gs_note_error(err) (err)
-#define return_error(err) return (err)
-#else
#define gs_note_error(err) gs_log_error(err, __FILE__, __LINE__)
#define return_error(err) return gs_note_error(err)
-#endif
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
# if defined(__GNUC__) && __GNUC__ >= 2
@@ -168,105 +163,6 @@ int gs_log_error(int, const char *, int);
const char *gs_errstr(int code);
-#ifdef GS_THREADSAFE
-/* In threadsafe builds, we just swallow errors unreported */
-#define gs_throw_code(code) \
- (code)
-
-#define gs_throw(code, fmt) \
- (code)
-#define gs_throw1(code, fmt, arg1) \
- (code)
-#define gs_throw2(code, fmt, arg1, arg2) \
- (code)
-#define gs_throw3(code, fmt, arg1, arg2, arg3) \
- (code)
-#define gs_throw4(code, fmt, arg1, arg2, arg3, arg4) \
- (code)
-#define gs_throw5(code, fmt, arg1, arg2, arg3, arg4, arg5) \
- (code)
-#define gs_throw6(code, fmt, arg1, arg2, arg3, arg4, arg5, arg6) \
- (code)
-#define gs_throw7(code, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
- (code)
-#define gs_throw8(code, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
- (code)
-#define gs_throw9(code, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
- (code)
-
-/* Bubble the code up the stack
-*/
-#define gs_rethrow_code(code) \
- (code)
-
-#define gs_rethrow(code, fmt) \
- (code)
-#define gs_rethrow1(code, fmt, arg1) \
- (code)
-#define gs_rethrow2(code, fmt, arg1, arg2) \
- (code)
-#define gs_rethrow3(code, fmt, arg1, arg2, arg3) \
- (code)
-#define gs_rethrow4(code, fmt, arg1, arg2, arg3, arg4) \
- (code)
-#define gs_rethrow5(code, fmt, arg1, arg2, arg3, arg4, arg5) \
- (code)
-#define gs_rethrow6(code, fmt, arg1, arg2, arg3, arg4, arg5, arg6) \
- (code)
-#define gs_rethrow7(code, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
- (code)
-#define gs_rethrow8(code, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
- (code)
-#define gs_rethrow9(code, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
- (code)
-
-/* This will cause trouble, as it implies you are fixing an error
- * the system will spew messages
- */
-#define gs_catch(code, fmt) \
- (code)
-#define gs_catch1(code, fmt, arg1) \
- (code)
-#define gs_catch2(code, fmt, arg1, arg2) \
- (code)
-#define gs_catch3(code, fmt, arg1, arg2, arg3) \
- (code)
-#define gs_catch4(code, fmt, arg1, arg2, arg3, arg4) \
- (code)
-#define gs_catch5(code, fmt, arg1, arg2, arg3, arg4, arg5) \
- (code)
-#define gs_catch6(code, fmt, arg1, arg2, arg3, arg4, arg5, arg6) \
- (code)
-#define gs_catch7(code, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
- (code)
-#define gs_catch8(code, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
- (code)
-#define gs_catch9(code, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
- (code)
-
-/* gs_warn is a printf
- */
-#define gs_warn(fmt) \
- DO_NOTHING
-#define gs_warn1(fmt, arg1) \
- DO_NOTHING
-#define gs_warn2(fmt, arg1, arg2) \
- DO_NOTHING
-#define gs_warn3(fmt, arg1, arg2, arg3) \
- DO_NOTHING
-#define gs_warn4(fmt, arg1, arg2, arg3, arg4) \
- DO_NOTHING
-#define gs_warn5(fmt, arg1, arg2, arg3, arg4, arg5) \
- DO_NOTHING
-#define gs_warn6(fmt, arg1, arg2, arg3, arg4, arg5, arg6) \
- DO_NOTHING
-#define gs_warn7(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
- DO_NOTHING
-#define gs_warn8(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
- DO_NOTHING
-#define gs_warn9(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
- DO_NOTHING
-#else
int gs_throw_imp(const char *func, const char *file, int line,
int op, int code, const char *fmt, ...) __printflike(6, 7);
@@ -368,7 +264,6 @@ int gs_throw_imp(const char *func, const char *file, int line,
(void)gs_throw_imp(__func__, __FILE__, __LINE__, 3, 0, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#define gs_warn9(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
(void)gs_throw_imp(__func__, __FILE__, __LINE__, 3, 0, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
-#endif
/* just in case you don't know 0 means no error
* other return codes are errors.
diff --git a/base/gsfcmap1.c b/base/gsfcmap1.c
index 0add2c744..249d74e61 100644
--- a/base/gsfcmap1.c
+++ b/base/gsfcmap1.c
@@ -23,6 +23,7 @@
#include "gsstruct.h"
#include "gsutil.h" /* for gs_next_ids */
#include "gxfcmap1.h"
+#include "gp.h"
/* Get a big-endian integer. */
static inline ulong
@@ -77,22 +78,24 @@ public_st_cmap_lookup_range_element();
* multi-dimensional range comparator
*/
-#ifndef GS_THREADSAFE
#ifdef DEBUG
static void
print_msg_str_in_range(const byte *str,
const byte *key_lo, const byte *key_hi,
int key_size)
{
- debug_print_string_hex_nomem(str, key_size);
- dlprintf(" in ");
- debug_print_string_hex_nomem(key_lo, key_size);
- dlprintf(" - ");
- debug_print_string_hex_nomem(key_hi, key_size);
- dlprintf("\n");
+ gs_memory_t *mem = gp_get_debug_mem_ptr();
+
+ if (mem == NULL)
+ return;
+ debug_print_string_hex(mem, str, key_size);
+ dmlprintf(mem, " in ");
+ debug_print_string_hex(mem, key_lo, key_size);
+ dmlprintf(mem, " - ");
+ debug_print_string_hex(mem, key_hi, key_size);
+ dmlprintf(mem, "\n");
}
#endif
-#endif
static int
gs_cmap_get_shortest_chr(const gx_code_map_t * pcmap, uint *pfidx)
@@ -128,14 +131,12 @@ gs_multidim_CID_offset(const byte *key_str,
int i; /* index for current dimension */
int CID_offset = 0;
-#ifndef GS_THREADSAFE
#ifdef DEBUG
if (gs_debug_c('J')) {
dlprintf("[J]gmCo() calc CID_offset for 0x");
print_msg_str_in_range(key_str, key_lo, key_hi, key_size);
}
#endif
-#endif
for (i = 0; i < key_size; i++)
CID_offset = CID_offset * (key_hi[i] - key_lo[i] + 1) +
@@ -183,7 +184,6 @@ code_map_decode_next_multidim_regime(const gx_code_map_t * pcmap,
*pchr = '\0';
-#ifndef GS_THREADSAFE
#ifdef DEBUG
if (gs_debug_c('J')) {
dlprintf("[J]CMDNmr() is called: str=(");
@@ -192,7 +192,6 @@ code_map_decode_next_multidim_regime(const gx_code_map_t * pcmap,
(intptr_t)str, ssize, pcmap->num_lookup);
}
#endif
-#endif
for (i = pcmap->num_lookup - 1; i >= 0; --i) {
/* main loop - scan the map passed via pcmap */
@@ -220,7 +219,6 @@ code_map_decode_next_multidim_regime(const gx_code_map_t * pcmap,
if (0 == j) /* no match, skip to next i */
continue;
else if (j < pre_size) { /* not exact, partial match */
-#ifndef GS_THREADSAFE
#ifdef DEBUG
if (gs_debug_c('J')) {
dlprintf("[J]CMDNmr() partial match with prefix:");
@@ -228,7 +226,6 @@ code_map_decode_next_multidim_regime(const gx_code_map_t * pcmap,
prefix, pre_size);
}
#endif
-#endif
if (pm_maxlen < j) {
pm_maxlen = chr_size;
pm_chr = bytes2int(str, chr_size);
@@ -238,14 +235,12 @@ code_map_decode_next_multidim_regime(const gx_code_map_t * pcmap,
continue ; /* no need to check key, skip to next i */
}
-#ifndef GS_THREADSAFE
#ifdef DEBUG
if (gs_debug_c('J')) {
dlprintf("[J]CMDNmr() full match with prefix:");
print_msg_str_in_range(str, prefix, prefix, pre_size);
}
#endif
-#endif
} /* if (0 < pre_size) */
/* full match in prefix. check key */
@@ -266,14 +261,12 @@ code_map_decode_next_multidim_regime(const gx_code_map_t * pcmap,
for (k = 0; k < pclr->num_entries; ++k, key += step) {
-#ifndef GS_THREADSAFE
#ifdef DEBUG
if_debug0('j', "[j]CMDNmr() check key:");
if (gs_debug_c('j'))
print_msg_str_in_range(str + pre_size,
key, key + step - key_size, key_size) ;
#endif
-#endif
for (l = 0; l < key_size; l++) {
byte c = str[l + pre_size];
@@ -302,7 +295,6 @@ code_map_decode_next_multidim_regime(const gx_code_map_t * pcmap,
*pfidx = pclr->font_index;
pvalue = pclr->values.data + k * pclr->value_size;
-#ifndef GS_THREADSAFE
#ifdef DEBUG
if (gs_debug_c('J')) {
dlprintf("[J]CMDNmr() full matched pvalue=(");
@@ -310,7 +302,6 @@ code_map_decode_next_multidim_regime(const gx_code_map_t * pcmap,
dlprintf(")\n");
}
#endif
-#endif
switch (pclr->value_type) {
case CODE_VALUE_CID:
@@ -343,7 +334,6 @@ code_map_decode_next_multidim_regime(const gx_code_map_t * pcmap,
*pfidx = pm_fidx;
*pglyph = GS_NO_GLYPH;
-#ifndef GS_THREADSAFE
#ifdef DEBUG
if (gs_debug_c('J')) {
dlprintf("[J]CMDNmr() no full match, use partial match for (");
@@ -351,7 +341,6 @@ code_map_decode_next_multidim_regime(const gx_code_map_t * pcmap,
dlprintf(")\n");
}
#endif
-#endif
return 0;
}
@@ -434,7 +423,6 @@ gs_cmap_adobe1_decode_next(const gs_cmap_t * pcmap_in,
*pglyph = GS_MIN_CID_GLYPH; /* CID = 0, this is CMap fallback */
*pindex = save_index + chr_size_shortest;
*pchr = '\0';
-#ifndef GS_THREADSAFE
#ifdef DEBUG
if (gs_debug_c('J')) {
const byte *str = pstr->data + save_index;
@@ -444,21 +432,18 @@ gs_cmap_adobe1_decode_next(const gs_cmap_t * pcmap_in,
dlprintf(")\n");
}
#endif
-#endif
return 0; /* should return some error for fallback .notdef? */
}
else {
/* Undecodable string is shorter than the shortest character,
* return 'GS_NO_GLYPH' and update index to end-of-string
*/
-#ifndef GS_THREADSAFE
#ifdef DEBUG
if (gs_debug_c('J')) {
dlprintf2("[J]GCDN() left data in buffer (%d) is shorter than shortest defined character (%d)\n",
ssize, chr_size_shortest);
}
#endif
-#endif
*pglyph = GS_NO_GLYPH;
*pindex += ssize;
return 0; /* fixme: should return a code != 0 if caller needs to know */
diff --git a/base/gshsb.c b/base/gshsb.c
index 1b92133e7..58e9424cb 100644
--- a/base/gshsb.c
+++ b/base/gshsb.c
@@ -150,7 +150,6 @@ color_hsb_to_rgb(double hue, double saturation, double brightness, float rgb[3])
rgb[0] = frac2float(R);
rgb[1] = frac2float(G);
rgb[2] = frac2float(B);
-#ifndef GS_THREADSAFE
#ifdef DEBUG
if (gs_debug_c('c')) {
dlprintf7("[c]hsb(%g,%g,%g)->VSFI(%ld,%d,%ld,%d)->\n",
@@ -159,6 +158,5 @@ color_hsb_to_rgb(double hue, double saturation, double brightness, float rgb[3])
R, G, B, rgb[0], rgb[1], rgb[2]);
}
#endif
-#endif
}
}
diff --git a/base/gsht.c b/base/gsht.c
index e9ad49a17..738c1661f 100644
--- a/base/gsht.c
+++ b/base/gsht.c
@@ -459,7 +459,6 @@ gx_sort_ht_order(gx_ht_bit * recs, uint N)
for (i = 0; i < N; i++)
recs[i].offset = i;
qsort((void *)recs, N, sizeof(*recs), compare_samples);
-#ifndef GS_THREADSAFE
#ifdef DEBUG
if (gs_debug_c('H')) {
uint i;
@@ -470,7 +469,6 @@ gx_sort_ht_order(gx_ht_bit * recs, uint N)
i, recs[i].offset, recs[i].mask);
}
#endif
-#endif
}
/*
diff --git a/base/gshtscr.c b/base/gshtscr.c
index 6807a9f37..29cd93e15 100644
--- a/base/gshtscr.c
+++ b/base/gshtscr.c
@@ -602,7 +602,7 @@ gs_screen_next(gs_screen_enum * penum, double value)
if (value < -1.0 || value > 1.0)
return_error(gs_error_rangecheck);
sample = (ht_sample_t) ((value + 1) * max_ht_sample);
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#if defined(DEBUG)
if (gs_debug_c('H')) {
gs_point pt;
diff --git a/base/gslibctx.c b/base/gslibctx.c
index 5690b86c1..abeafaab8 100644
--- a/base/gslibctx.c
+++ b/base/gslibctx.c
@@ -53,6 +53,7 @@
#include "cal.h"
#endif
#include "gsargs.h"
+#include "globals.h"
/* Include the extern for the device list. */
extern_gs_lib_device_list();
@@ -68,16 +69,6 @@ gs_lib_ctx_get_real_stdio(FILE **in, FILE **out, FILE **err)
#include "gslibctx.h"
#include "gsmemory.h"
-#ifndef GS_THREADSAFE
-static gs_memory_t *mem_err_print = NULL;
-
-gs_memory_t *
-gs_lib_ctx_get_non_gc_memory_t()
-{
- return mem_err_print ? mem_err_print : NULL;
-}
-#endif
-
/* This sets the directory to prepend to the ICC profile names specified for
defaultgray, defaultrgb, defaultcmyk, proofing, linking, named color and device */
int
@@ -270,10 +261,6 @@ int gs_lib_ctx_init(gs_lib_ctx_t *ctx, gs_memory_t *mem)
if (mem == 0 || mem != mem->non_gc_memory)
return_error(gs_error_Fatal);
-#ifndef GS_THREADSAFE
- mem_err_print = mem;
-#endif
-
if (mem->gs_lib_ctx) /* one time initialization */
return 0;
@@ -301,6 +288,7 @@ int gs_lib_ctx_init(gs_lib_ctx_t *ctx, gs_memory_t *mem)
return -1;
}
memset(pio->core, 0, sizeof(*pio->core));
+ pio->core->globals = gp_get_globals();
pio->core->fs = (gs_fs_list_t *)gs_alloc_bytes_immovable(mem,
sizeof(gs_fs_list_t),
"gs_lib_ctx_init(gs_fs_list_t)");
@@ -431,10 +419,6 @@ void gs_lib_ctx_fin(gs_memory_t *mem)
gs_free_object(ctx_mem, ctx->io_device_table_root, "gs_lib_ctx_fin");
gs_free_object(ctx_mem, ctx->font_dir_root, "gs_lib_ctx_fin");
-#ifndef GS_THREADSAFE
- mem_err_print = NULL;
-#endif
-
gx_monitor_enter((gx_monitor_t *)(ctx->core->monitor));
refs = --ctx->core->refs;
gx_monitor_leave((gx_monitor_t *)(ctx->core->monitor));
@@ -526,13 +510,6 @@ int outwrite(const gs_memory_t *mem, const char *str, int len)
return code;
}
-#ifndef GS_THREADSAFE
-int errwrite_nomem(const char *str, int len)
-{
- return errwrite(mem_err_print, str, len);
-}
-#endif
-
int errwrite(const gs_memory_t *mem, const char *str, int len)
{
int code;
@@ -541,13 +518,11 @@ int errwrite(const gs_memory_t *mem, const char *str, int len)
if (len == 0)
return 0;
if (mem == NULL) {
-#ifdef GS_THREADSAFE
- return 0;
-#else
- mem = mem_err_print;
+#ifdef DEBUG
+ mem = gp_get_debug_mem_ptr();
if (mem == NULL)
- return 0;
#endif
+ return 0;
}
ctx = mem->gs_lib_ctx;
if (ctx == NULL)
@@ -576,13 +551,6 @@ void outflush(const gs_memory_t *mem)
fflush(core->fstdout);
}
-#ifndef GS_THREADSAFE
-void errflush_nomem(void)
-{
- errflush(mem_err_print);
-}
-#endif
-
void errflush(const gs_memory_t *mem)
{
if (!mem->gs_lib_ctx->core->stderr_fn)
@@ -1362,3 +1330,39 @@ int gs_lib_ctx_callout(gs_memory_t *mem, const char *dev_name,
}
return -1;
}
+
+int gs_lib_ctx_nts_adjust(gs_memory_t *mem, int adjust)
+{
+ gs_lib_ctx_core_t *core;
+ int ret = 0;
+ gs_globals *globals;
+
+ if (adjust == 0)
+ return 0;
+
+ if (mem == NULL || mem->gs_lib_ctx == NULL || mem->gs_lib_ctx->core == NULL)
+ return_error(gs_error_unknownerror);
+
+ core = mem->gs_lib_ctx->core;
+ globals = core->globals;
+ if (globals == NULL)
+ return 0; /* No globals means just once instance. Adjustment is pointless. */
+
+ gp_global_lock(globals);
+ if (adjust > 0 && globals->non_threadsafe_count != 0)
+ ret = gs_error_unknownerror; /* We already have one non threadsafe device running. */
+ else if (adjust < 0 && globals->non_threadsafe_count == 0)
+ ret = gs_error_unknownerror; /* This indicates something has gone very wrong! */
+ else
+ globals->non_threadsafe_count += adjust;
+ gp_global_unlock(globals);
+
+ if (ret)
+ ret = gs_note_error(ret);
+ return ret;
+}
+
+void gs_globals_init(gs_globals *globals)
+{
+ memset(globals, 0, sizeof(*globals));
+}
diff --git a/base/gslibctx.h b/base/gslibctx.h
index 0acb520cf..9d1aa921d 100644
--- a/base/gslibctx.h
+++ b/base/gslibctx.h
@@ -94,6 +94,8 @@ typedef struct gs_callout_list_s {
void *handle;
} gs_callout_list_t;
+typedef struct gs_globals gs_globals;
+
typedef struct {
void *monitor;
int refs;
@@ -137,6 +139,8 @@ typedef struct {
int arg_max;
int argc;
char **argv;
+
+ gs_globals *globals;
} gs_lib_ctx_core_t;
typedef struct gs_lib_ctx_s
@@ -213,14 +217,7 @@ int gs_lib_ctx_register_callout(gs_memory_t *mem, gs_callout_fn, void *arg);
void gs_lib_ctx_deregister_callout(gs_memory_t *mem, gs_callout_fn, void *arg);
int gs_lib_ctx_callout(gs_memory_t *mem, const char *dev_name,
int id, int size, void *data);
-
-
-#ifndef GS_THREADSAFE
-/* HACK to get at non garbage collection memory pointer
- *
- */
-gs_memory_t * gs_lib_ctx_get_non_gc_memory_t(void);
-#endif
+int gs_lib_ctx_nts_adjust(gs_memory_t *mem, int adjust);
int gs_lib_ctx_set_icc_directory(const gs_memory_t *mem_gc, const char* pname,
int dir_namelen);
diff --git a/base/gsmalloc.c b/base/gsmalloc.c
index e5eae62ec..8875e39b9 100644
--- a/base/gsmalloc.c
+++ b/base/gsmalloc.c
@@ -24,6 +24,7 @@
#include "gsstruct.h" /* for st_bytes */
#include "gsmalloc.h"
#include "gsmemret.h" /* retrying wrapper */
+#include "gp.h"
/* ------ Heap allocator ------ */
@@ -607,6 +608,8 @@ gs_malloc_init_with_context(gs_lib_ctx_t *ctx)
if (malloc_memory_default == NULL)
return NULL;
+ gp_set_debug_mem_ptr((gs_memory_t *)malloc_memory_default);
+
if (gs_lib_ctx_init(ctx, (gs_memory_t *)malloc_memory_default) != 0) {
gs_malloc_release((gs_memory_t *)malloc_memory_default);
return NULL;
diff --git a/base/gsmisc.c b/base/gsmisc.c
index db73c007c..f6273a5b1 100644
--- a/base/gsmisc.c
+++ b/base/gsmisc.c
@@ -47,6 +47,7 @@ orig_sqrt(double x)
#include "gxfixed.h"
#include "stdint_.h"
#include "stdio_.h"
+#include "gp.h"
/* ------ Redirected stdout and stderr ------ */
@@ -73,25 +74,26 @@ int outprintf(const gs_memory_t *mem, const char *fmt, ...)
return count;
}
-#ifndef GS_THREADSAFE
int errprintf_nomem(const char *fmt, ...)
{
int count;
char buf[PRINTF_BUF_LENGTH];
va_list args;
+ gs_memory_t *mem = gp_get_debug_mem_ptr();
+ if (mem == NULL)
+ return 0;
va_start(args, fmt);
count = vsnprintf(buf, sizeof(buf), fmt, args);
if (count < 0 || count >= sizeof(buf)) { /* MSVC || C99*/
- errwrite_nomem(buf, sizeof(buf) - 1);
- errwrite_nomem(msg_truncated, sizeof(msg_truncated) - 1);
+ errwrite(mem, buf, sizeof(buf) - 1);
+ errwrite(mem, msg_truncated, sizeof(msg_truncated) - 1);
} else {
- errwrite_nomem(buf, count);
+ errwrite(mem, buf, count);
}
va_end(args);
return count;
}
-#endif
int errprintf(const gs_memory_t *mem, const char *fmt, ...)
{
@@ -159,11 +161,12 @@ dprintf_file_tail(const char *file)
--tail;
return tail;
}
-#ifndef GS_THREADSAFE
void
dflush(void)
{
- errflush_nomem();
+ gs_memory_t *mem = gp_get_debug_mem_ptr();
+ if (mem)
+ errflush(mem);
}
#if __LINE__ /* compiler provides it */
void
@@ -207,7 +210,6 @@ eprintf_program_ident(const char *program_name,
epf(": ");
}
}
-#endif
#if __LINE__ /* compiler provides it */
void
dmprintf_file_and_line(const gs_memory_t *mem,const char *file, int line)
@@ -303,12 +305,15 @@ gs_return_check_interrupt(const gs_memory_t *mem, int code)
}
}
-#ifndef GS_THREADSAFE
int gs_throw_imp(const char *func, const char *file, int line, int op, int code, const char *fmt, ...)
{
char msg[1024];
va_list ap;
int count;
+ gs_memory_t *mem = gp_get_debug_mem_ptr();
+
+ if (mem == NULL)
+ return code;
va_start(ap, fmt);
count = vsnprintf(msg, sizeof(msg), fmt, ap);
@@ -325,26 +330,25 @@ int gs_throw_imp(const char *func, const char *file, int line, int op, int code,
/* throw */
if (op == 0)
- errprintf_nomem("+ %s:%d: %s(): %s\n", file, line, func, msg);
+ errprintf(mem, "+ %s:%d: %s(): %s\n", file, line, func, msg);
/* rethrow */
if (op == 1)
- errprintf_nomem("| %s:%d: %s(): %s\n", file, line, func, msg);
+ errprintf(mem, "| %s:%d: %s(): %s\n", file, line, func, msg);
/* catch */
if (op == 2)
- errprintf_nomem("- %s:%d: %s(): %s\n", file, line, func, msg);
+ errprintf(mem, "- %s:%d: %s(): %s\n", file, line, func, msg);
/* warn */
if (op == 3)
- errprintf_nomem(" %s:%d: %s(): %s\n", file, line, func, msg);
+ errprintf(mem, " %s:%d: %s(): %s\n", file, line, func, msg);
if (count < 0 || count >= sizeof(msg)) { /* MSVC || C99 */
- errwrite_nomem(msg_truncated, sizeof(msg_truncated) - 1);
+ errwrite(mem, msg_truncated, sizeof(msg_truncated) - 1);
}
return code;
}
-#endif
const char *gs_errstr(int code)
{
@@ -542,7 +546,7 @@ gs_realloc(void *old_ptr, size_t old_size, size_t new_size)
/* ------ Debugging support ------ */
-#ifndef GS_THREADSAFE
+#ifdef DEBUG
/* Print a string in hexdump format. */
void
debug_print_string_hex_nomem(const byte * chrs, uint len)
@@ -615,7 +619,7 @@ debug_print_string_hex(const gs_memory_t *mem, const byte * chrs, uint len)
* first_arg is the first argument of the procedure into which this code
* is patched.
*/
-#ifndef GS_THREADSAFE
+#ifdef DEBUG
#define BACKTRACE(first_arg)\
BEGIN\
ulong *fp_ = (ulong *)&first_arg - 2;\
@@ -935,7 +939,7 @@ fixed_mult_quo(fixed signed_A, fixed B, fixed C)
double
gs_sqrt(double x, const char *file, int line)
{
-#ifndef GS_THREADSAFE
+#ifdef DEBUG
if (gs_debug_c('~')) {
dprintf3("[~]sqrt(%g) at %s:%d\n", x, (const char *)file, line);
dflush();
diff --git a/base/gxblend.c b/base/gxblend.c
index e4a643d8f..37e086ef2 100644
--- a/base/gxblend.c
+++ b/base/gxblend.c
@@ -1345,10 +1345,8 @@ art_blend_pixel_8_inline(byte *gs_restrict dst, const byte *gs_restrict backdrop
break;
}
default:
-#ifndef GS_THREADSAFE
dlprintf1("art_blend_pixel_8: blend mode %d not implemented\n",
blend_mode);
-#endif
memcpy(dst, src, n_chan);
break;
}
@@ -1556,10 +1554,8 @@ art_blend_pixel_16_inline(uint16_t *gs_restrict dst, const uint16_t *gs_restrict
break;
}
default:
-#ifndef GS_THREADSAFE
dlprintf1("art_blend_pixel_16: blend mode %d not implemented\n",
blend_mode);
-#endif
memcpy(dst, src, n_chan*2);
break;
}
diff --git a/base/gxcldev.h b/base/gxcldev.h
index ccac8e5a8..11bbd9397 100644
--- a/base/gxcldev.h
+++ b/base/gxcldev.h
@@ -457,7 +457,9 @@ dev_proc_get_bits_rectangle(clist_get_bits_rectangle);
int cmd_put_params(gx_device_clist_writer *, gs_param_list *);
/* Conditionally keep command statistics. */
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+/* #define COLLECT_STATS_CLIST */
+
+#ifdef COLLECT_STATS_CLIST
int cmd_count_op(int op, uint size, const gs_memory_t *mem);
int cmd_count_extended_op(int op, uint size, const gs_memory_t *mem);
void cmd_uncount_op(int op, uint size);
diff --git a/base/gxclip.c b/base/gxclip.c
index 3cad4695a..d29a8783e 100644
--- a/base/gxclip.c
+++ b/base/gxclip.c
@@ -202,7 +202,9 @@ gx_make_clip_device_in_heap(gx_device_clip *dev,
(void)(*dev_proc(dev, open_device)) ((gx_device *)dev);
}
/* Define debugging statistics for the clipping loops. */
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+/* #define COLLECT_STATS_CLIP */
+
+#ifdef COLLECT_STATS_CLIP
struct stats_clip_s {
long
loops, out, in_y, in, in1, down, up, x, no_x;
@@ -234,7 +236,7 @@ clip_enumerate_rest(gx_device_clip * rdev,
int yc;
int code;
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_CLIP
if (INCR(loops) % clip_interval == 0 && gs_debug_c('q')) {
dmprintf5(rdev->memory,
"[q]loops=%ld out=%ld in_y=%ld in=%ld in1=%ld\n",
diff --git a/base/gxclpath.c b/base/gxclpath.c
index c7fc1f479..670c61d83 100644
--- a/base/gxclpath.c
+++ b/base/gxclpath.c
@@ -37,7 +37,7 @@
#include "gxdevsop.h"
/* Statistics */
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_CLIST
ulong stats_cmd_diffs[5];
#endif
diff --git a/base/gxclutil.c b/base/gxclutil.c
index 027be65bc..a5a32c2f9 100644
--- a/base/gxclutil.c
+++ b/base/gxclutil.c
@@ -51,7 +51,7 @@ const char *const *const cmd_sub_op_names[16] =
const char *cmd_extend_op_names[256] =
{cmd_extend_op_name_strings};
-#ifndef GS_THREADSAFE
+#ifdef COLLECT_STATS_CLIST
struct stats_cmd_s {
ulong op_counts[512];
ulong op_sizes[512];
@@ -105,7 +105,7 @@ cmd_uncount_op(int op, uint size)
#endif
/* Print statistics. */
-#if defined(DEBUG_CLIST_STATS) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_CLIST
void
cmd_print_stats(const gs_memory_t *mem)
{
@@ -325,7 +325,7 @@ cmd_write_buffer(gx_device_clist_writer * cldev, byte cmd_end)
VALGRIND_MAKE_MEM_UNDEFINED(cldev->cbuf, cldev->cend - cldev->cbuf);
#endif
cldev->ccl = 0;
-#if defined(DEBUG_CLIST_STATS) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_CLIST
if (gs_debug_c('l'))
cmd_print_stats(cldev->memory);
#endif
diff --git a/base/gxdevice.h b/base/gxdevice.h
index c01950e9d..c1eb563b3 100644
--- a/base/gxdevice.h
+++ b/base/gxdevice.h
@@ -680,4 +680,7 @@ int gx_subclass_composite(gx_device *dev, gx_device **pcdev, const gs_composite_
gs_gstate *pgs, gs_memory_t *memory, gx_device *cdev);
void gx_subclass_fill_in_page_procs(gx_device *dev);
+int gx_init_non_threadsafe_device(gx_device *dev);
+
+
#endif /* gxdevice_INCLUDED */
diff --git a/base/gxfill.c b/base/gxfill.c
index 88e44c992..518468003 100644
--- a/base/gxfill.c
+++ b/base/gxfill.c
@@ -80,7 +80,7 @@
#define TRY_TO_EXTEND_TRAP 0
#endif
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_FILL
/* Define the statistics structure instance. */
stats_fill_t stats_fill;
#endif
@@ -525,7 +525,7 @@ gx_general_fill_path(gx_device * pdev, const gs_gstate * pgs,
free_line_list(&lst);
if (pfpath != ppath) /* had to flatten */
gx_path_free(pfpath, "gx_general_fill_path");
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_FILL
if (gs_debug_c('f')) {
dmlputs(ppath->memory,
"[f] # alloc up down horiz step slowx iter find band bstep bfill\n");
diff --git a/base/gxfill.h b/base/gxfill.h
index c4616a096..0f37e69e0 100644
--- a/base/gxfill.h
+++ b/base/gxfill.h
@@ -155,7 +155,9 @@ struct line_list_s {
/* ---------------- Statistics ---------------- */
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+/* #define COLLECT_STATS_FILL */
+
+#ifdef COLLECT_STATS_FILL
struct stats_fill_s {
long
fill, fill_alloc, y_up, y_down, horiz, x_step, slow_x, iter, find_y,
diff --git a/base/gxifast.c b/base/gxifast.c
index 7ec7a1de7..967e4f536 100644
--- a/base/gxifast.c
+++ b/base/gxifast.c
@@ -39,9 +39,7 @@
#include "valgrind.h"
/* Conditionally include statistics code. */
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
-# define STATS
-#endif
+/* #define COLLECT_STATS_IFAST */
/* ------ Strategy procedure ------ */
@@ -195,7 +193,7 @@ image_render_skip(gx_image_enum * penum, const byte * buffer, int data_x,
* other bits in those bytes are set to zero (i.e., the value of the
* 'zero' argument).
*/
-#ifdef STATS
+#ifdef COLLECT_STATS_IFAST
struct stats_image_fast_s {
long
calls, all0s, all1s, runs, lbit0, byte00, byte01, byte02, byte03,
diff --git a/base/gxpflat.c b/base/gxpflat.c
index 928a24c2d..61d43ee48 100644
--- a/base/gxpflat.c
+++ b/base/gxpflat.c
@@ -203,8 +203,7 @@ gx_flattened_iterator__init(gx_flattened_iterator *self,
return false;
self->curve = true;
self->k = k;
-#ifndef GS_THREADSAFE
-# ifdef DEBUG
+#ifdef DEBUG
if (gs_debug_c('3')) {
dlprintf4("[3]x0=%f y0=%f x1=%f y1=%f\n",
fixed2float(self->x0), fixed2float(self->y0),
@@ -213,7 +212,6 @@ gx_flattened_iterator__init(gx_flattened_iterator *self,
fixed2float(x2), fixed2float(y2),
fixed2float(self->x3), fixed2float(self->y3), self->k);
}
-# endif
#endif
if (k == -1) {
/* A special hook for gx_subdivide_curve_rec.
@@ -333,7 +331,7 @@ gx_flattened_iterator__init_line(gx_flattened_iterator *self,
return true;
}
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef DEBUG
static inline void
gx_flattened_iterator__print_state(gx_flattened_iterator *self)
{
@@ -418,7 +416,7 @@ gx_flattened_iterator__next(gx_flattened_iterator *self)
--self->i;
if (self->i == 0)
goto last; /* don't bother with last accum */
-# if defined(DEBUG) && !defined(GS_THREADSAFE)
+# ifdef DEBUG
gx_flattened_iterator__print_state(self);
# endif
# define accum(i, r, di, dr, rmask)\
@@ -490,7 +488,7 @@ gx_flattened_iterator__prev(gx_flattened_iterator *self)
}
gx_flattened_iterator__unaccum(self);
self->i++;
-# if defined(DEBUG) && !defined(GS_THREADSAFE)
+# ifdef DEBUG
if_debug5('3', "[3]%s x=%g, y=%g x=%ld y=%ld\n",
(((self->x ^ self->lx1) | (self->y ^ self->ly1)) & float2fixed(-0.5) ?
"add" : "skip"),
diff --git a/base/gxstroke.c b/base/gxstroke.c
index e77023179..6fc63eea2 100644
--- a/base/gxstroke.c
+++ b/base/gxstroke.c
@@ -1401,7 +1401,7 @@ line_intersect(
double f1;
double max_result = any_abs(denom) * (double)max_fixed;
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef DEBUG
if (gs_debug_c('O')) {
dlprintf4("[o]Intersect %f,%f(%f/%f)",
fixed2float(pp1->x), fixed2float(pp1->y),
@@ -1744,7 +1744,7 @@ check_miter(const gx_line_params * pgs_lp, pl_ptr plp, pl_ptr nplp,
* we actually have to do the test backwards.
*/
ccw0 = v1 * u2 < v2 * u1;
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef DEBUG
{
double a1 = atan2(u1, v1), a2 = atan2(u2, v2), dif = a1 - a2;
@@ -1767,7 +1767,7 @@ check_miter(const gx_line_params * pgs_lp, pl_ptr plp, pl_ptr nplp,
*/
if (!ccw0) /* have plp - nplp, want vice versa */
num = -num;
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef DEBUG
if (gs_debug_c('O')) {
dlprintf4("[o]Miter check: u1/v1=%f/%f, u2/v2=%f/%f,\n",
u1, v1, u2, v2);
@@ -2515,7 +2515,7 @@ compute_caps(pl_ptr plp)
plp->o.ce.x = plp->o.p.x - wx2, plp->o.ce.y = plp->o.p.y - wy2;
plp->e.co.x = plp->e.p.x - wx2, plp->e.co.y = plp->e.p.y - wy2;
plp->e.ce.x = plp->e.p.x + wx2, plp->e.ce.y = plp->e.p.y + wy2;
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef DEBUG
if (gs_debug_c('O')) {
dlprintf4("[o]Stroke o=(%f,%f) e=(%f,%f)\n",
fixed2float(plp->o.p.x), fixed2float(plp->o.p.y),
diff --git a/base/lib.mak b/base/lib.mak
index f8b69cf61..ed0fa38a7 100644
--- a/base/lib.mak
+++ b/base/lib.mak
@@ -101,6 +101,7 @@ srdline_h=$(GLSRC)srdline.h
gpgetenv_h=$(GLSRC)gpgetenv.h
gpmisc_h=$(GLSRC)gpmisc.h
gp_h=$(GLSRC)gp.h
+globals_h=$(GLSRC)globals.h
gpcheck_h=$(GLSRC)gpcheck.h
gpsync_h=$(GLSRC)gpsync.h
@@ -239,7 +240,7 @@ $(GLOBJ)gsalloc.$(OBJ) : $(GLSRC)gsalloc.c $(AK) $(gx_h) $(gserrors_h)\
$(GLCC) $(GLO_)gsalloc.$(OBJ) $(C_) $(GLSRC)gsalloc.c
$(GLOBJ)gsmalloc.$(OBJ) : $(GLSRC)gsmalloc.c $(malloc__h)\
- $(gdebug_h)\
+ $(gdebug_h) $(gp_h) \
$(gserrors_h)\
$(gsmalloc_h) $(gsmdebug_h) $(gsmemret_h)\
$(gsmemory_h) $(gsstruct_h) $(gstypes_h) $(LIB_MAK) $(MAKEDIRS)
@@ -349,7 +350,7 @@ $(GLOBJ)gsargs.$(OBJ) : $(GLSRC)gsargs.c\
$(GLOBJ)gsmisc.$(OBJ) : $(GLSRC)gsmisc.c $(AK) $(gx_h) $(gserrors_h)\
$(vmsmath_h) $(std_h) $(ctype__h) $(malloc__h) $(math__h) $(memory__h)\
$(string__h) $(gpcheck_h) $(gxfarith_h) $(gxfixed_h) $(stdint__h) $(stdio__h)\
- $(gdbflags_h) $(LIB_MAK) $(MAKEDIRS)
+ $(gdbflags_h) $(gp_h) $(LIB_MAK) $(MAKEDIRS)
$(GLCC) $(GLO_)gsmisc.$(OBJ) $(C_) $(GLSRC)gsmisc.c
$(AUX)gsmisc.$(OBJ) : $(GLSRC)gsmisc.c $(AK) $(gx_h) $(gpmisc_h) $(gserrors_h)\
@@ -358,9 +359,9 @@ $(AUX)gsmisc.$(OBJ) : $(GLSRC)gsmisc.c $(AK) $(gx_h) $(gpmisc_h) $(gserrors_h)\
$(gdbflags_h) $(LIB_MAK) $(MAKEDIRS)
$(GLCCAUX) $(C_) $(AUXO_)gsmisc.$(OBJ) $(GLSRC)gsmisc.c
-$(GLOBJ)gslibctx_1.$(OBJ) : $(GLSRC)gslibctx.c $(AK) $(gp_h) $(gpmisc_h) $(gsmemory_h)\
- $(gslibctx_h) $(stdio__h) $(string__h) $(gsicc_manage_h) $(gserrors_h)\
- $(gscdefs_h) $(gsstruct_h)
+$(GLOBJ)gslibctx_1.$(OBJ) : $(GLSRC)gslibctx.c $(AK) $(gp_h) $(gpmisc_h) \
+ $(gsmemory_h) $(gslibctx_h) $(stdio__h) $(string__h) $(gsicc_manage_h) \
+ $(gserrors_h) $(gscdefs_h) $(gsstruct_h) $(globals_h)
$(GLCC) $(D_)WITH_CAL$(_D) $(I_)$(CALSRCDIR)$(_I) $(GLO_)gslibctx_1.$(OBJ) $(C_) $(GLSRC)gslibctx.c
$(GLOBJ)gslibctx_0.$(OBJ) : $(GLSRC)gslibctx.c $(AK) $(gp_h) $(gpmisc_h) $(gsmemory_h)\
@@ -3726,7 +3727,7 @@ $(GLD)nosync.dev : $(LIB_MAK) $(ECHOGS_XE) $(nosync_) $(LIB_MAK) $(MAKEDIRS)
$(SETMOD) $(GLD)nosync $(nosync_)
$(GLOBJ)gp_nsync.$(OBJ) : $(GLSRC)gp_nsync.c $(AK) $(std_h)\
- $(gpsync_h) $(gserrors_h) $(LIB_MAK) $(MAKEDIRS)
+ $(gpsync_h) $(gp_h) $(globals_h) $(gserrors_h) $(LIB_MAK) $(MAKEDIRS)
$(GLCC) $(GLO_)gp_nsync.$(OBJ) $(C_) $(GLSRC)gp_nsync.c
# POSIX pthreads-based implementation.
@@ -3736,8 +3737,8 @@ $(GLD)posync.dev : $(LIB_MAK) $(ECHOGS_XE) $(pthreads_) $(LIB_MAK) $(MAKEDIRS)
$(ADDMOD) $(GLD)posync -replace $(GLD)nosync
$(GLOBJ)gp_psync.$(OBJ) : $(GLSRC)gp_psync.c $(AK) $(malloc__h) $(string__h) \
- $(std_h) $(gpsync_h) $(gserrors_h) $(assert__h) $(unistd__h) $(LIB_MAK)\
- $(MAKEDIRS)
+ $(std_h) $(gpsync_h) $(gserrors_h) $(assert__h) $(unistd__h) $(globals_h) \
+ $(gp_h) $(LIB_MAK) $(MAKEDIRS)
$(GLCC) $(GLO_)gp_psync.$(OBJ) $(C_) $(GLSRC)gp_psync.c
# Other stuff.
@@ -3975,6 +3976,7 @@ $(GLSRC)gp.h:$(GLSRC)stat_.h
$(GLSRC)gp.h:$(GLSRC)gsstype.h
$(GLSRC)gp.h:$(GLSRC)gsmemory.h
$(GLSRC)gp.h:$(GLSRC)gpgetenv.h
+$(GLSRC)gp.h:$(GLSRC)globals.h
$(GLSRC)gp.h:$(GLSRC)gscdefs.h
$(GLSRC)gp.h:$(GLSRC)gslibctx.h
$(GLSRC)gp.h:$(GLSRC)stdio_.h
@@ -4075,6 +4077,8 @@ $(GLSRC)gsgc.h:$(GLSRC)stdint_.h
$(GLSRC)gsgc.h:$(GLSRC)std.h
$(GLSRC)gsgc.h:$(GLSRC)stdpre.h
$(GLSRC)gsgc.h:$(GLGEN)arch.h
+$(GLSRC)globals.h:$(GLSRC)std.h
+$(GLSRC)globals.h:$(GLSRC)gslibctx.h
$(GLSRC)gsmalloc.h:$(GLSRC)gxsync.h
$(GLSRC)gsmalloc.h:$(GLSRC)gpsync.h
$(GLSRC)gsmalloc.h:$(GLSRC)gsmemory.h
diff --git a/base/mkromfs.c b/base/mkromfs.c
index 08fbb27d8..d46450b5d 100644
--- a/base/mkromfs.c
+++ b/base/mkromfs.c
@@ -248,36 +248,43 @@ int errprintf_nomem(const char *fmt, ...)
return count;
}
-#ifndef GS_THREADSAFE
#if __LINE__ /* compiler provides it */
void
lprintf_file_and_line(const char *file, int line)
{
- errprintf(NULL, "%s(%d): ", file, line);
+ errprintf_nomem("%s(%d): ", file, line);
}
#else
void
lprintf_file_only(FILE * f, const char *file)
{
- errprintf(NULL, "%s(?): ", file);
+ errprintf_nomem("%s(?): ", file);
}
#endif
+gs_memory_t *gp_get_debug_mem_ptr(void)
+{
+ return NULL;
+}
+
void
eprintf_program_ident(const char *program_name,
long revision_number)
{
+ gs_memory_t *mem = gp_get_debug_mem_ptr();
+
+ if (mem == NULL)
+ return;
if (program_name) {
- errprintf(NULL, (revision_number ? "%s " : "%s"), program_name);
+ errprintf(mem, (revision_number ? "%s " : "%s"), program_name);
if (revision_number) {
int fpart = revision_number % 100;
- errprintf(NULL, "%d.%02d", (int)(revision_number / 100), fpart);
+ errprintf(mem, "%d.%02d", (int)(revision_number / 100), fpart);
}
- errprintf(NULL, ": ");
+ errprintf(mem, ": ");
}
}
-#endif
void
emprintf_program_ident(const gs_memory_t *mem,
diff --git a/base/scfe.c b/base/scfe.c
index 15e1a4902..98648e988 100644
--- a/base/scfe.c
+++ b/base/scfe.c
@@ -25,9 +25,9 @@
/* ------ Macros and support routines ------ */
/* Statistics */
+/* #define COLLECT_STATS_SCFE */
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
-
+#ifdef COLLECT_STATS_SCFE
typedef struct stats_runs_s {
ulong termination[64];
ulong make_up[41];
@@ -52,7 +52,7 @@ print_run_stats(const gs_memory_t *mem, const stats_runs_t * stats)
dmprintf1(mem, " total=%lu\n", total);
}
-#else /* !DEBUG || defined(GS_THREADSAFE) */
+#else /* !defined(COLLECT_STATS_SCFE) */
#define COUNT_RUN(cnt, i) DO_NOTHING
@@ -82,10 +82,9 @@ cf_put_long_run(stream_CFE_state * ss, byte * q, int lenv, const cf_runs * prt)
hce_declare_state;
cfe_run rr;
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_SCFE
stats_runs_t *pstats =
(prt == &cf_white_runs ? &stats_white_runs : &stats_black_runs);
-
#endif
hce_load_state();
@@ -374,11 +373,12 @@ s_CFE_process(stream_state * st, stream_cursor_read * pr,
status, ss->read_count, ss->write_count,
(intptr_t) pr->ptr, (int)(rlimit - pr->ptr), (intptr_t) rlimit,
(intptr_t) pw->ptr, (int)(wlimit - pw->ptr), (intptr_t) wlimit);
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef DEBUG
if (pr->ptr > rlimit || pw->ptr > wlimit) {
lprintf("Pointer overrun!\n");
status = ERRC;
}
+#ifdef COLLECT_STATS_SCFE
if (gs_debug_c('w') && status == 1) {
dmlputs(ss->memory, "[w]white runs:");
print_run_stats(ss->memory, &stats_white_runs);
@@ -386,6 +386,7 @@ s_CFE_process(stream_state * st, stream_cursor_read * pr,
print_run_stats(ss->memory, &stats_black_runs);
}
#endif
+#endif
return status;
}
diff --git a/base/shc.h b/base/shc.h
index b7ae66d14..a52e5bc72 100644
--- a/base/shc.h
+++ b/base/shc.h
@@ -105,7 +105,7 @@ typedef struct hce_table_s {
* that q does not exceed pw->limit.
*/
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#if defined(DEBUG)
# define hc_print_value(code, clen)\
(gs_debug_c('W') ?\
(dlprintf2("[W]0x%x,%d\n", code, clen), 0) : 0)
diff --git a/base/std.h b/base/std.h
index 36025ba53..78f14ac62 100644
--- a/base/std.h
+++ b/base/std.h
@@ -128,8 +128,8 @@ typedef ulong bits32;
*
* If you do not have a gs_memory_t * to hand, then you may call dprintf (and
* family) and eprintf(and family) insteads. Be aware that these functions
- * compile away to nothing in GS_THREADSAFE builds, as they will not work in
- * multithreaded environments.
+ * compile away to nothing in non-DEBUG builds (and even in some DEBUG
+ * environments), as they rely on platform specific threading tricks.
*
* Since we all stdout/stderr output must go via outprintf/errprintf,
* we have to define dputc and dputs in terms of errprintf also.
@@ -156,10 +156,8 @@ typedef struct gs_memory_s gs_memory_t;
#define dpfm errprintf
#define epfm errprintf
-#ifndef GS_THREADSAFE
#define dpf errprintf_nomem
#define epf errprintf_nomem
-#endif /* GS_THREADSAFE */
/* To allow stdout and stderr to be redirected, all stdout goes
* though outwrite and all stderr goes through errwrite.
@@ -170,14 +168,6 @@ int errwrite(const gs_memory_t *mem, const char *str, int len);
void outflush(const gs_memory_t *mem);
void errflush(const gs_memory_t *mem);
-#ifndef GS_THREADSAFE
-/* As a temporary measure, we allow forms of errwrite/errflush that do not
- * need to be given a memory pointer. Any uses of this (largely the debugging
- * system) will fail with multithreaded usage. */
-int errwrite_nomem(const char *str, int len);
-void errflush_nomem(void);
-#endif /* GS_THREADSAFE */
-
/* Formatted output to outwrite and errwrite.
* The maximum string length is 1023 characters.
*/
@@ -193,77 +183,19 @@ void errflush_nomem(void);
# endif
int outprintf(const gs_memory_t *mem, const char *fmt, ...) __printflike(2, 3);
int errprintf(const gs_memory_t *mem, const char *fmt, ...) __printflike(2, 3);
-#ifndef GS_THREADSAFE
int errprintf_nomem(const char *fmt, ...) __printflike(1, 2);
-#endif
#else
int outprintf();
int errprintf();
-#ifndef GS_THREADSAFE
int errprintf_nomem();
#endif
-#endif
-/* Print the program line # for debugging - NON THREADSAFE VERSIONS */
-#ifdef GS_THREADSAFE
-#define dflush() DO_NOTHING
-#define dputc(chr) DO_NOTHING
-#define dlputc(chr) DO_NOTHING
-#define dputs(str) DO_NOTHING
-#define dlputs(str) DO_NOTHING
-#define dprintf(str)\
- DO_NOTHING
-#define dlprintf(str)\
- DO_NOTHING
-#define dprintf1(str,arg1)\
- DO_NOTHING
-#define dlprintf1(str,arg1)\
- DO_NOTHING
-#define dprintf2(str,arg1,arg2)\
- DO_NOTHING
-#define dlprintf2(str,arg1,arg2)\
- DO_NOTHING
-#define dprintf3(str,arg1,arg2,arg3)\
- DO_NOTHING
-#define dlprintf3(str,arg1,arg2,arg3)\
- DO_NOTHING
-#define dprintf4(str,arg1,arg2,arg3,arg4)\
- DO_NOTHING
-#define dlprintf4(str,arg1,arg2,arg3,arg4)\
- DO_NOTHING
-#define dprintf5(str,arg1,arg2,arg3,arg4,arg5)\
- DO_NOTHING
-#define dlprintf5(str,arg1,arg2,arg3,arg4,arg5)\
- DO_NOTHING
-#define dprintf6(str,arg1,arg2,arg3,arg4,arg5,arg6)\
- DO_NOTHING
-#define dlprintf6(str,arg1,arg2,arg3,arg4,arg5,arg6)\
- DO_NOTHING
-#define dprintf7(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7)\
- DO_NOTHING
-#define dlprintf7(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7)\
- DO_NOTHING
-#define dprintf8(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)\
- DO_NOTHING
-#define dlprintf8(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)\
- DO_NOTHING
-#define dprintf9(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\
- DO_NOTHING
-#define dlprintf9(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\
- DO_NOTHING
-#define dprintf10(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\
- DO_NOTHING
-#define dlprintf10(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\
- DO_NOTHING
-#define dprintf11(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)\
- DO_NOTHING
-#define dlprintf11(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)\
- DO_NOTHING
-#define dprintf12(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)\
- DO_NOTHING
-#define dlprintf12(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)\
- DO_NOTHING
-#else
+/* Print the program line # for debugging */
+/* These versions do not take a memory pointer, and hence have to
+ * appeal to platform specific methods to get one from thread local
+ * storage. These are likely to be much slower than the other versions,
+ * and, on some platforms at least, may do nothing. Avoid these if
+ * possible. */
#if __LINE__ /* compiler provides it */
void dprintf_file_and_line(const char *, int);
# define _dpl dprintf_file_and_line(__FILE__, __LINE__),
@@ -329,7 +261,6 @@ void dflush(void); /* flush stderr */
dpf(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)
#define dlprintf12(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)\
(_dpl dprintf12(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12))
-#endif /* GS_THREADSAFE */
/* Print the program line # for debugging. */
#if __LINE__ /* compiler provides it */
@@ -400,11 +331,6 @@ void dmprintf_file_only(const gs_memory_t *,const char *);
void printf_program_ident(const gs_memory_t *mem, const char *program_name, long revision_number);
-#ifdef GS_THREADSAFE
-#define eprintf_program_ident(NAME,NUM) DO_NOTHING
-#else
-void eprintf_program_ident(const char *program_name, long revision_number);
-#endif /* GS_THREADSAFE */
void emprintf_program_ident(const gs_memory_t *mem,
const char *program_name,
long revision_number);
@@ -412,30 +338,12 @@ const char *gs_program_family_name(void);
const char *gs_program_name(void);
long gs_revision_number(void);
-#ifdef GS_THREADSAFE
-#define eprintf(str)\
- DO_NOTHING
-#define eprintf1(str,arg1)\
- DO_NOTHING
-#define eprintf2(str,arg1,arg2)\
- DO_NOTHING
-#define eprintf3(str,arg1,arg2,arg3)\
- DO_NOTHING
-#define eprintf4(str,arg1,arg2,arg3,arg4)\
- DO_NOTHING
-#define eprintf5(str,arg1,arg2,arg3,arg4,arg5)\
- DO_NOTHING
-#define eprintf6(str,arg1,arg2,arg3,arg4,arg5,arg6)\
- DO_NOTHING
-#define eprintf7(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7)\
- DO_NOTHING
-#define eprintf8(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)\
- DO_NOTHING
-#define eprintf9(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\
- DO_NOTHING
-#define eprintf10(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\
- DO_NOTHING
-#else
+/* These versions do not take a memory pointer, and hence have to
+ * appeal to platform specific methods to get one from thread local
+ * storage. These are likely to be much slower than the other versions,
+ * and, on some platforms at least, may do nothing. Avoid these if
+ * possible. */
+void eprintf_program_ident(const char *program_name, long revision_number);
#define _epi eprintf_program_ident(gs_program_name(), gs_revision_number()),
#define eprintf(str)\
@@ -460,7 +368,6 @@ long gs_revision_number(void);
(_epi epf(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9))
#define eprintf10(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\
(_epi epf(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10))
-#endif /* GS_THREADSAFE */
#define _epim(mem) emprintf_program_ident(mem, gs_program_name(), gs_revision_number()),
@@ -487,30 +394,6 @@ long gs_revision_number(void);
#define emprintf10(mem, str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\
(_epim(mem) epfm(mem, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10))
-#ifdef GS_THREADSAFE
-#define lprintf(str)\
- DO_NOTHING
-#define lprintf1(str,arg1)\
- DO_NOTHING
-#define lprintf2(str,arg1,arg2)\
- DO_NOTHING
-#define lprintf3(str,arg1,arg2,arg3)\
- DO_NOTHING
-#define lprintf4(str,arg1,arg2,arg3,arg4)\
- DO_NOTHING
-#define lprintf5(str,arg1,arg2,arg3,arg4,arg5)\
- DO_NOTHING
-#define lprintf6(str,arg1,arg2,arg3,arg4,arg5,arg6)\
- DO_NOTHING
-#define lprintf7(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7)\
- DO_NOTHING
-#define lprintf8(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)\
- DO_NOTHING
-#define lprintf9(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\
- DO_NOTHING
-#define lprintf10(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\
- DO_NOTHING
-#else
#if __LINE__ /* compiler provides it */
void lprintf_file_and_line(const char *, int);
# define _epl _epi lprintf_file_and_line(__FILE__, __LINE__),
@@ -541,7 +424,6 @@ void lprintf_file_only(const char *);
(_epl epf(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9))
#define lprintf10(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\
(_epl epf(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10))
-#endif /* GS_THREADSAFE */
#if __LINE__ /* compiler provides it */
void mlprintf_file_and_line(const gs_memory_t *,const char *, int);
diff --git a/base/ttinterp.c b/base/ttinterp.c
index 2ac1783b2..fe44a844e 100644
--- a/base/ttinterp.c
+++ b/base/ttinterp.c
@@ -88,7 +88,9 @@
# define DBG_PRINT4(fmt, a, b, c, d)
#endif
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+/* #define COLLECT_STATS_TTINTERP */
+
+#ifdef COLLECT_STATS_TTINTERP
static int nInstrCount=0;
#endif
@@ -4952,7 +4954,7 @@ static int nInstrCount=0;
Int A;
PDefRecord WITH;
PCallRecord WITH1;
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_TTINTERP
bool bFirst;
#endif
bool dbg_prt = (DBG_PRT_FUN != NULL);
@@ -5002,7 +5004,7 @@ static int nInstrCount=0;
CUR.error = Result;
goto _LExit;
}
-#if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_TTINTERP
bFirst = true;
#endif
do
@@ -5037,7 +5039,7 @@ static int nInstrCount=0;
CUR.step_ins = TRUE;
CUR.error = TT_Err_Ok;
-# if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_TTINTERP
DBG_PRINT3("\n%%n=%5d IP=%5d OP=%s ", nInstrCount, CUR.IP, Instruct_Dispatch[CUR.opcode].sName);
/*
{ for(int i=0;i<CUR.top;i++)
@@ -5050,11 +5052,11 @@ static int nInstrCount=0;
memcpy(save_cx, CUR.pts.cur_x, sizeof(CUR.pts.cur_x[0]) * CUR.pts.n_points);
memcpy(save_cy, CUR.pts.cur_y, sizeof(CUR.pts.cur_y[0]) * CUR.pts.n_points);
}
-# endif
+#endif
Instruct_Dispatch[CUR.opcode].p( EXEC_ARGS &CUR.stack[CUR.args] );
-# if defined(DEBUG) && !defined(GS_THREADSAFE)
+#ifdef COLLECT_STATS_TTINTERP
if (save_ox != NULL) {
F26Dot6 *pp[4], *qq[4];
const char *ss[] = {"org.x", "org.y", "cur.x", "cur.y"};
@@ -5084,7 +5086,7 @@ static int nInstrCount=0;
nInstrCount++;
bFirst=FALSE;
}
-# endif
+#endif
DBG_PAINT
diff --git a/base/winplat.mak b/base/winplat.mak
index b53a5ec7d..0fc57698f 100644
--- a/base/winplat.mak
+++ b/base/winplat.mak
@@ -67,7 +67,7 @@ $(GLD)winsync.dev : $(WINPLAT_MAK) $(ECHOGS_XE) $(winsync_) $(WINPLAT_MAK)
$(GLOBJ)gp_wsync.$(OBJ): $(GLSRC)gp_wsync.c $(AK)\
$(dos__h) $(malloc__h) $(stdio__h) $(string__h) $(windows__h)\
- $(gp_h) $(gsmemory_h) $(gstypes_h) $(WINPLAT_MAK)
+ $(gp_h) $(gsmemory_h) $(gstypes_h) $(globals_h) $(WINPLAT_MAK)
$(GLCCWIN) $(GLO_)gp_wsync.$(OBJ) $(C_) $(GLSRC)gp_wsync.c
# The XPS printer