diff options
author | Robin Watts <Robin.Watts@artifex.com> | 2021-11-05 17:16:32 +0000 |
---|---|---|
committer | Robin Watts <Robin.Watts@artifex.com> | 2021-11-05 17:59:23 +0000 |
commit | 86154fe0b961c1cf996c06626bba4a2be07e0cb9 (patch) | |
tree | 26641ac43a2930b3ed6b735b898f36b579626157 /demos | |
parent | a3524c6d0b1315de80724768889c90a6c1683a83 (diff) | |
download | ghostpdl-86154fe0b961c1cf996c06626bba4a2be07e0cb9.tar.gz |
Add simple Ghostscript/GhostPDL multi-instance example.
Diffstat (limited to 'demos')
-rw-r--r-- | demos/c/Makefile | 14 | ||||
-rw-r--r-- | demos/c/ReadMe.txt | 40 | ||||
-rw-r--r-- | demos/c/multi_test.c | 176 |
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; +} |