summaryrefslogtreecommitdiff
path: root/demos/c/multi_test.c
blob: f62d3e6eaf3029f3ac1dafd59371c9c32ba4513a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/* Copyright (C) 2018-2022 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.
*/

/* 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;
}