1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimppluginhsm.c
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "config.h"
21
22 #include <sys/types.h>
23
24 #include <errno.h>
25
26 #if defined(USE_SYSV_SHM)
27
28 #ifdef HAVE_IPC_H
29 #include <sys/ipc.h>
30 #endif
31
32 #ifdef HAVE_SHM_H
33 #include <sys/shm.h>
34 #endif
35
36 #elif defined(USE_POSIX_SHM)
37
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41
42 #include <fcntl.h>
43 #include <sys/mman.h>
44
45 #endif /* USE_POSIX_SHM */
46
47 #include <gio/gio.h>
48 #include <gegl.h>
49
50 #if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
51
52 #define STRICT
53 #include <windows.h>
54 #include <process.h>
55
56 #ifdef G_OS_WIN32
57 #include <fcntl.h>
58 #include <io.h>
59 #endif
60
61 #define USE_WIN32_SHM 1
62
63 #endif /* G_OS_WIN32 || G_WITH_CYGWIN */
64
65 #include "plug-in-types.h"
66
67 #include "core/gimp-utils.h"
68
69 #include "gimppluginshm.h"
70
71 #include "gimp-log.h"
72
73
74 #define TILE_MAP_SIZE (GIMP_PLUG_IN_TILE_WIDTH * GIMP_PLUG_IN_TILE_HEIGHT * 32)
75
76 #define ERRMSG_SHM_DISABLE "Disabling shared memory tile transport"
77
78
79 struct _GimpPlugInShm
80 {
81 gint shm_ID;
82 guchar *shm_addr;
83
84 #if defined(USE_WIN32_SHM)
85 HANDLE shm_handle;
86 #endif
87 };
88
89
90 GimpPlugInShm *
gimp_plug_in_shm_new(void)91 gimp_plug_in_shm_new (void)
92 {
93 /* allocate a piece of shared memory for use in transporting tiles
94 * to plug-ins. if we can't allocate a piece of shared memory then
95 * we'll fall back on sending the data over the pipe.
96 */
97
98 GimpPlugInShm *shm = g_slice_new0 (GimpPlugInShm);
99
100 shm->shm_ID = -1;
101
102 #if defined(USE_SYSV_SHM)
103
104 /* Use SysV shared memory mechanisms for transferring tile data. */
105 {
106 shm->shm_ID = shmget (IPC_PRIVATE, TILE_MAP_SIZE, IPC_CREAT | 0600);
107
108 if (shm->shm_ID != -1)
109 {
110 shm->shm_addr = (guchar *) shmat (shm->shm_ID, NULL, 0);
111
112 if (shm->shm_addr == (guchar *) -1)
113 {
114 g_printerr ("shmat() failed: %s\n" ERRMSG_SHM_DISABLE,
115 g_strerror (errno));
116 shmctl (shm->shm_ID, IPC_RMID, NULL);
117 shm->shm_ID = -1;
118 }
119
120 #ifdef IPC_RMID_DEFERRED_RELEASE
121 if (shm->shm_addr != (guchar *) -1)
122 shmctl (shm->shm_ID, IPC_RMID, NULL);
123 #endif
124 }
125 else
126 {
127 g_printerr ("shmget() failed: %s\n" ERRMSG_SHM_DISABLE,
128 g_strerror (errno));
129 }
130 }
131
132 #elif defined(USE_WIN32_SHM)
133
134 /* Use Win32 shared memory mechanisms for transferring tile data. */
135 {
136 gint pid;
137 gchar fileMapName[MAX_PATH];
138
139 /* Our shared memory id will be our process ID */
140 pid = GetCurrentProcessId ();
141
142 /* From the id, derive the file map name */
143 g_snprintf (fileMapName, sizeof (fileMapName), "GIMP%d.SHM", pid);
144
145 /* Create the file mapping into paging space */
146 shm->shm_handle = CreateFileMapping (INVALID_HANDLE_VALUE, NULL,
147 PAGE_READWRITE, 0,
148 TILE_MAP_SIZE,
149 fileMapName);
150
151 if (shm->shm_handle)
152 {
153 /* Map the shared memory into our address space for use */
154 shm->shm_addr = (guchar *) MapViewOfFile (shm->shm_handle,
155 FILE_MAP_ALL_ACCESS,
156 0, 0, TILE_MAP_SIZE);
157
158 /* Verify that we mapped our view */
159 if (shm->shm_addr)
160 {
161 shm->shm_ID = pid;
162 }
163 else
164 {
165 g_printerr ("MapViewOfFile error: %d... " ERRMSG_SHM_DISABLE,
166 GetLastError ());
167 }
168 }
169 else
170 {
171 g_printerr ("CreateFileMapping error: %d... " ERRMSG_SHM_DISABLE,
172 GetLastError ());
173 }
174 }
175
176 #elif defined(USE_POSIX_SHM)
177
178 /* Use POSIX shared memory mechanisms for transferring tile data. */
179 {
180 gint pid;
181 gchar shm_handle[32];
182 gint shm_fd;
183
184 /* Our shared memory id will be our process ID */
185 pid = gimp_get_pid ();
186
187 /* From the id, derive the file map name */
188 g_snprintf (shm_handle, sizeof (shm_handle), "/gimp-shm-%d", pid);
189
190 /* Create the file mapping into paging space */
191 shm_fd = shm_open (shm_handle, O_RDWR | O_CREAT, 0600);
192
193 if (shm_fd != -1)
194 {
195 if (ftruncate (shm_fd, TILE_MAP_SIZE) != -1)
196 {
197 /* Map the shared memory into our address space for use */
198 shm->shm_addr = (guchar *) mmap (NULL, TILE_MAP_SIZE,
199 PROT_READ | PROT_WRITE, MAP_SHARED,
200 shm_fd, 0);
201
202 /* Verify that we mapped our view */
203 if (shm->shm_addr != MAP_FAILED)
204 {
205 shm->shm_ID = pid;
206 }
207 else
208 {
209 g_printerr ("mmap() failed: %s\n" ERRMSG_SHM_DISABLE,
210 g_strerror (errno));
211
212 shm_unlink (shm_handle);
213 }
214 }
215 else
216 {
217 g_printerr ("ftruncate() failed: %s\n" ERRMSG_SHM_DISABLE,
218 g_strerror (errno));
219
220 shm_unlink (shm_handle);
221 }
222
223 close (shm_fd);
224 }
225 else
226 {
227 g_printerr ("shm_open() failed: %s\n" ERRMSG_SHM_DISABLE,
228 g_strerror (errno));
229 }
230 }
231
232 #endif
233
234 if (shm->shm_ID == -1)
235 {
236 g_slice_free (GimpPlugInShm, shm);
237 shm = NULL;
238 }
239 else
240 {
241 GIMP_LOG (SHM, "attached shared memory segment ID = %d", shm->shm_ID);
242 }
243
244 return shm;
245 }
246
247 void
gimp_plug_in_shm_free(GimpPlugInShm * shm)248 gimp_plug_in_shm_free (GimpPlugInShm *shm)
249 {
250 g_return_if_fail (shm != NULL);
251
252 if (shm->shm_ID != -1)
253 {
254
255 #if defined (USE_SYSV_SHM)
256
257 shmdt (shm->shm_addr);
258
259 #ifndef IPC_RMID_DEFERRED_RELEASE
260 shmctl (shm->shm_ID, IPC_RMID, NULL);
261 #endif
262
263 #elif defined(USE_WIN32_SHM)
264
265 if (shm->shm_handle)
266 CloseHandle (shm->shm_handle);
267
268 #elif defined(USE_POSIX_SHM)
269
270 gchar shm_handle[32];
271
272 munmap (shm->shm_addr, TILE_MAP_SIZE);
273
274 g_snprintf (shm_handle, sizeof (shm_handle), "/gimp-shm-%d",
275 shm->shm_ID);
276
277 shm_unlink (shm_handle);
278
279 #endif
280
281 GIMP_LOG (SHM, "detached shared memory segment ID = %d", shm->shm_ID);
282 }
283
284 g_slice_free (GimpPlugInShm, shm);
285 }
286
287 gint
gimp_plug_in_shm_get_ID(GimpPlugInShm * shm)288 gimp_plug_in_shm_get_ID (GimpPlugInShm *shm)
289 {
290 g_return_val_if_fail (shm != NULL, -1);
291
292 return shm->shm_ID;
293 }
294
295 guchar *
gimp_plug_in_shm_get_addr(GimpPlugInShm * shm)296 gimp_plug_in_shm_get_addr (GimpPlugInShm *shm)
297 {
298 g_return_val_if_fail (shm != NULL, NULL);
299
300 return shm->shm_addr;
301 }
302