summaryrefslogtreecommitdiff
path: root/demos
diff options
context:
space:
mode:
authorRobin Watts <Robin.Watts@artifex.com>2021-11-05 17:16:32 +0000
committerRobin Watts <Robin.Watts@artifex.com>2021-11-05 17:59:23 +0000
commit86154fe0b961c1cf996c06626bba4a2be07e0cb9 (patch)
tree26641ac43a2930b3ed6b735b898f36b579626157 /demos
parenta3524c6d0b1315de80724768889c90a6c1683a83 (diff)
downloadghostpdl-86154fe0b961c1cf996c06626bba4a2be07e0cb9.tar.gz
Add simple Ghostscript/GhostPDL multi-instance example.
Diffstat (limited to 'demos')
-rw-r--r--demos/c/Makefile14
-rw-r--r--demos/c/ReadMe.txt40
-rw-r--r--demos/c/multi_test.c176
3 files changed, 230 insertions, 0 deletions
diff --git a/demos/c/Makefile b/demos/c/Makefile
index 63dc4da56..5f053410d 100644
--- a/demos/c/Makefile
+++ b/demos/c/Makefile
@@ -10,3 +10,17 @@ run_api_test: api_test
post_api_test:
md5sum apitest*
rm apitest*
+
+multi_test: multi_test.c
+ (cd ../.. && ./autogen.sh)
+ (cd ../.. && make so XCFLAGS="-DCLUSTER")
+ pwd
+ gcc -fPIC -I../.. multi_test.c -DGHOSTPDL=1 -lgpdl -lpthread -L../../sobin -o multi_test
+
+run_multi_test: multi_test
+ LD_LIBRARY_PATH=../../sobin ./multi_test
+
+post_multi_test:
+ md5sum multitest*
+ rm multitest*
+ rm multi_out*
diff --git a/demos/c/ReadMe.txt b/demos/c/ReadMe.txt
index 16c4d9de6..336a31fb6 100644
--- a/demos/c/ReadMe.txt
+++ b/demos/c/ReadMe.txt
@@ -29,3 +29,43 @@ tested there. Some fiddling to load the DLL may be required.
Building with GHOSTPDL=0 will allow the Ghostscript DLL to be
tested. The VS2019 project will need to be edited to use the
appropriate .lib file too.
+
+On unix, the file can be built using:
+
+ make api_test
+
+run using:
+
+ make run_api_test
+
+and cleaned up using:
+
+ make post_api_test
+
+
+ multi_test
+ ~~~~~~~~~~
+
+This is a simple VS2019 project that loads the gpdl dll and drives
+multiple instances of it from the gsapi functions.
+
+It is intended as a simple demonstration of how to use multiple
+instances of the ghostscript library at once; in this case many
+ghostscript instances run in parallel within a single process
+to convert several different documents at a time.
+
+Building with GHOSTPDL=0 will allow the Ghostscript DLL to be
+tested. The VS2019 project will need to be edited to use the
+appropriate .lib file too.
+
+On unix, the file can be built using:
+
+ make multi_test
+
+run using:
+
+ make run_multi_test
+
+and cleaned up using:
+
+ make post_multi_test
diff --git a/demos/c/multi_test.c b/demos/c/multi_test.c
new file mode 100644
index 000000000..487a36582
--- /dev/null
+++ b/demos/c/multi_test.c
@@ -0,0 +1,176 @@
+/* Simple example file to demonstrate multi-instance use of
+ * the ghostscript/GPDL library. */
+
+#ifdef _WIN32
+/* Stop windows builds complaining about sprintf being insecure. */
+#define _CRT_SECURE_NO_WARNINGS
+#include <windows.h>
+#define WINDOWS
+#else
+#include <pthread.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <assert.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+/* This can work either with the Ghostscript or GhostPDL
+ * library. The code is the same for both. */
+#if GHOSTPDL
+#include "pcl/pl/plapi.h" /* GSAPI - gpdf version */
+#else
+#include "psi/iapi.h" /* GSAPI - ghostscript version */
+#endif
+
+/* We hold details of each threads working in a thread_data
+ * structure. */
+typedef struct
+{
+ /* What worker number are we ? */
+ int thread_num;
+ /* What input file? should this worker use? */
+ char *in_file;
+ /* Somewhere to store the thread id */
+#ifdef WINDOWS
+ HANDLE thread;
+#else
+ pthread_t thread;
+#endif
+ /* exit code for the thread */
+ int code;
+} thread_data;
+
+/* The function to perform the work of the thread.
+ * Starts a gs instance, runs a file, shuts it down.
+ */
+static
+#ifdef WINDOWS
+DWORD WINAPI
+#else
+void *
+#endif
+worker(void *td_)
+{
+ thread_data *td = (thread_data *)td_;
+ int code;
+ void *instance = NULL;
+ char out[32];
+
+ /* Construct the argc/argv to pass to ghostscript. */
+ int argc = 0;
+ char *argv[10];
+
+ sprintf(out, "multi_out_%d_", td->thread_num);
+ strcat(out, "%%d.png");
+ argv[argc++] = "gpdl";
+ argv[argc++] = "-sDEVICE=png16m";
+ argv[argc++] = "-o";
+ argv[argc++] = out;
+ argv[argc++] = "-r100";
+ argv[argc++] = td->in_file;
+
+ /* Create a GS instance. */
+ code = gsapi_new_instance(&instance, NULL);
+ if (code < 0) {
+ printf("Error %d in gsapi_new_instance\n", code);
+ goto failearly;
+ }
+
+ /* Run our test. */
+ code = gsapi_init_with_args(instance, argc, argv);
+ if (code < 0) {
+ printf("Error %d in gsapi_init_with_args\n", code);
+ goto fail;
+ }
+
+ /* Close the interpreter down (important, or we will leak!) */
+ code = gsapi_exit(instance);
+ if (code < 0) {
+ printf("Error %d in gsapi_exit\n", code);
+ goto fail;
+ }
+
+fail:
+ /* Delete the gs instance. */
+ gsapi_delete_instance(instance);
+
+failearly:
+ td->code = code;
+
+#ifdef WINDOWS
+ return 0;
+#else
+ return NULL;
+#endif
+}
+
+/* A list of input files to run. */
+char *in_files[] =
+{
+ "../../examples/tiger.eps",
+ "../../examples/golfer.eps",
+ "../../examples/escher.ps",
+ "../../examples/snowflak.ps"
+#ifdef GHOSTPDL
+ , "../../pcl/examples/grashopp.pcl"
+ , "../../pcl/examples/owl.pcl"
+ , "../../pcl/examples/tiger.xps"
+#endif
+};
+
+#define NUM_INPUTS (sizeof(in_files)/sizeof(*in_files))
+#define NUM_WORKERS (10)
+
+int main(int argc, char *argv[])
+{
+ int failed = 0;
+#ifndef WINDOWS
+ int code;
+#endif
+ int i;
+ thread_data td[NUM_WORKERS];
+
+ /* Start NUM_WORKERS threads */
+ for (i = 0; i < NUM_WORKERS; i++)
+ {
+ td[i].in_file = in_files[i % NUM_INPUTS];
+ td[i].thread_num = i;
+
+#ifdef WINDOWS
+ td[i].thread = CreateThread(NULL, 0, worker, &td[i], 0, NULL);
+#else
+ code = pthread_create(&td[i].thread, NULL, worker, &td[i]);
+ if (code != 0) {
+ fprintf(stderr, "Thread %d creation failed\n", i);
+ exit(1);
+ }
+#endif
+ }
+
+ /* Wait for them all to finish */
+ for (i = 0; i < NUM_WORKERS; i++)
+ {
+ void *status = NULL;
+
+#ifdef WINDOWS
+ WaitForSingleObject(td[i].thread, INFINITE);
+#else
+ code = pthread_join(td[i].thread, &status);
+ if (code != 0) {
+ fprintf(stderr, "Thread join %d failed\n", i);
+ exit(1);
+ }
+#endif
+ /* All the threads should return with 0 */
+ if (td[i].code != 0)
+ failed = 1;
+ fprintf(stderr, "Thread %d finished with %d\n", i, td[i].code);
+ }
+
+ return failed;
+}