]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/shm.cc
* Merge in cygwin-64bit-branch.
[newlib-cygwin.git] / winsup / cygwin / shm.cc
CommitLineData
a6df500f 1/* shm.cc: XSI IPC interface for Cygwin.
f449bfef 2
61522196
CV
3 Copyright 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2012, 2013
4 Red Hat, Inc.
f449bfef 5
2402700d 6This file is part of Cygwin.
f449bfef 7
2402700d
CF
8This software is a copyrighted work licensed under the terms of the
9Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10details. */
f449bfef
RC
11
12#include "winsup.h"
a6df500f 13#include <sys/queue.h>
1c001dd2
CS
14#include <unistd.h>
15
a6df500f 16#include "pinfo.h"
1c001dd2
CS
17#include "sigproc.h"
18
f449bfef 19#include "cygserver_shm.h"
893ac8e0 20#include "cygtls.h"
03abe23b 21#include "sync.h"
1e4e6ee8 22#include "ntdll.h"
f449bfef 23
a6df500f
CV
24/*
25 * client_request_shm Constructors
1c001dd2 26 */
1c001dd2 27
a6df500f
CV
28client_request_shm::client_request_shm (int shmid,
29 const void *shmaddr,
30 int shmflg)
31 : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
f449bfef 32{
a6df500f
CV
33 _parameters.in.shmop = SHMOP_shmat;
34 ipc_set_proc_info (_parameters.in.ipcblk);
1c001dd2 35
a6df500f
CV
36 _parameters.in.atargs.shmid = shmid;
37 _parameters.in.atargs.shmaddr = shmaddr;
38 _parameters.in.atargs.shmflg = shmflg;
1c001dd2 39
a6df500f 40 msglen (sizeof (_parameters.in));
f449bfef
RC
41}
42
a6df500f
CV
43client_request_shm::client_request_shm (int shmid,
44 int cmd,
45 struct shmid_ds *buf)
46 : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
f449bfef 47{
a6df500f
CV
48 _parameters.in.shmop = SHMOP_shmctl;
49 ipc_set_proc_info (_parameters.in.ipcblk);
1c001dd2 50
a6df500f
CV
51 _parameters.in.ctlargs.shmid = shmid;
52 _parameters.in.ctlargs.cmd = cmd;
53 _parameters.in.ctlargs.buf = buf;
1c001dd2 54
a6df500f 55 msglen (sizeof (_parameters.in));
f449bfef
RC
56}
57
a6df500f
CV
58client_request_shm::client_request_shm (const void *shmaddr)
59 : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
f449bfef 60{
a6df500f
CV
61 _parameters.in.shmop = SHMOP_shmdt;
62 ipc_set_proc_info (_parameters.in.ipcblk);
f449bfef 63
a6df500f 64 _parameters.in.dtargs.shmaddr = shmaddr;
f449bfef 65
a6df500f 66 msglen (sizeof (_parameters.in));
f449bfef
RC
67}
68
a6df500f
CV
69client_request_shm::client_request_shm (key_t key,
70 size_t size,
71 int shmflg)
72 : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
67be0adb 73{
a6df500f
CV
74 _parameters.in.shmop = SHMOP_shmget;
75 ipc_set_proc_info (_parameters.in.ipcblk);
67be0adb 76
a6df500f
CV
77 _parameters.in.getargs.key = key;
78 _parameters.in.getargs.size = size;
79 _parameters.in.getargs.shmflg = shmflg;
1c001dd2 80
a6df500f
CV
81 msglen (sizeof (_parameters.in));
82}
1c001dd2 83
a6df500f
CV
84client_request_shm::client_request_shm (proc *p1)
85 : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
86{
87 _parameters.in.shmop = SHMOP_shmfork;
88 ipc_set_proc_info (_parameters.in.ipcblk);
1c001dd2 89
a6df500f
CV
90 _parameters.in.forkargs = *p1;
91}
1c001dd2 92
a6df500f
CV
93/* List of shmid's with file mapping HANDLE and size, returned by shmget. */
94struct shm_shmid_list {
7d9c458d 95 SLIST_ENTRY (shm_shmid_list) ssh_next;
a6df500f
CV
96 int shmid;
97 vm_object_t hdl;
98 size_t size;
03abe23b 99 int ref_count;
a6df500f 100};
1c001dd2 101
7d9c458d 102static SLIST_HEAD (, shm_shmid_list) ssh_list;
1c001dd2 103
a6df500f
CV
104/* List of attached mappings, as returned by shmat. */
105struct shm_attached_list {
7d9c458d 106 SLIST_ENTRY (shm_attached_list) sph_next;
a6df500f 107 vm_object_t ptr;
03abe23b 108 shm_shmid_list *parent;
1e4e6ee8 109 ULONG access;
a6df500f 110};
67be0adb 111
7d9c458d 112static SLIST_HEAD (, shm_attached_list) sph_list;
1c001dd2 113
03abe23b
CV
114static NO_COPY muto shm_guard;
115#define SLIST_LOCK() (shm_guard.init ("shm_guard")->acquire ())
116#define SLIST_UNLOCK() (shm_guard.release ())
117
a6df500f
CV
118int __stdcall
119fixup_shms_after_fork ()
f449bfef 120{
a6df500f
CV
121 if (!SLIST_FIRST (&sph_list))
122 return 0;
123 pinfo p (myself->ppid);
124 proc parent = { myself->ppid, p->dwProcessId, p->uid, p->gid };
1c001dd2 125
a6df500f
CV
126 client_request_shm request (&parent);
127 if (request.make_request () == -1 || request.retval () == -1)
f449bfef 128 {
6b0d86c5 129 syscall_printf ("-1 [%d] = fixup_shms_after_fork ()", request.error_code ());
1c001dd2 130 set_errno (request.error_code ());
a6df500f
CV
131 return 0;
132 }
133 shm_attached_list *sph_entry;
1e4e6ee8 134 /* Reconstruct map from list... */
a6df500f
CV
135 SLIST_FOREACH (sph_entry, &sph_list, sph_next)
136 {
1e4e6ee8
CV
137 NTSTATUS status;
138 vm_object_t ptr = sph_entry->ptr;
61522196 139 SIZE_T viewsize = sph_entry->parent->size;
f16706de 140 status = NtMapViewOfSection (sph_entry->parent->hdl, NtCurrentProcess (),
1e4e6ee8
CV
141 &ptr, 0, sph_entry->parent->size, NULL,
142 &viewsize, ViewShare, 0, sph_entry->access);
143 if (!NT_SUCCESS (status) || ptr != sph_entry->ptr)
61522196 144 api_fatal ("fixup_shms_after_fork: NtMapViewOfSection (%p), status %y. Terminating.",
1e4e6ee8 145 sph_entry->ptr, status);
f449bfef
RC
146 }
147 return 0;
148}
149
a6df500f
CV
150/*
151 * XSI shmaphore API. These are exported by the DLL.
152 */
f449bfef 153
a6df500f
CV
154extern "C" void *
155shmat (int shmid, const void *shmaddr, int shmflg)
1c001dd2 156{
61522196 157 syscall_printf ("shmat (shmid = %d, shmaddr = %p, shmflg = %y)",
a6df500f 158 shmid, shmaddr, shmflg);
f449bfef 159
03abe23b 160 SLIST_LOCK ();
a6df500f
CV
161 shm_shmid_list *ssh_entry;
162 SLIST_FOREACH (ssh_entry, &ssh_list, ssh_next)
f449bfef 163 {
a6df500f
CV
164 if (ssh_entry->shmid == shmid)
165 break;
f449bfef 166 }
a6df500f 167 if (!ssh_entry)
f449bfef 168 {
5c7b73ed 169 /* The shmid is unknown to this process so far. Try to get it from
e3778517 170 the server if it exists. Use special internal call to shmget,
5c7b73ed
CV
171 which interprets the key as a shmid and only returns a valid
172 shmid if one exists. Since shmctl inserts a new entry for this
173 shmid into ssh_list automatically, we just have to go through
174 that list again. If that still fails, well, bad luck. */
175 if (shmid && shmget ((key_t) shmid, 0, IPC_KEY_IS_SHMID) != -1)
e3778517 176 {
5c7b73ed
CV
177 SLIST_FOREACH (ssh_entry, &ssh_list, ssh_next)
178 {
179 if (ssh_entry->shmid == shmid)
180 break;
181 }
182 }
183 if (!ssh_entry)
e3778517 184 {
5c7b73ed
CV
185 /* Invalid shmid */
186 set_errno (EINVAL);
03abe23b 187 SLIST_UNLOCK ();
5c7b73ed
CV
188 return (void *) -1;
189 }
f449bfef 190 }
03abe23b
CV
191 /* Early increment ref counter. This allows further actions to run with
192 unlocked lists, because shmdt or shmctl(IPC_RMID) won't delete this
193 ssh_entry. */
194 ++ssh_entry->ref_count;
195 SLIST_UNLOCK ();
196
a6df500f
CV
197 vm_object_t attach_va = NULL;
198 if (shmaddr)
f449bfef 199 {
a6df500f 200 if (shmflg & SHM_RND)
e3778517 201 attach_va = (vm_object_t)((vm_offset_t)shmaddr & ~(SHMLBA-1));
a6df500f
CV
202 else
203 attach_va = (vm_object_t)shmaddr;
204 /* Don't even bother to call anything if shmaddr is NULL or
e3778517 205 not aligned. */
a6df500f
CV
206 if (!attach_va || (vm_offset_t)attach_va % SHMLBA)
207 {
208 set_errno (EINVAL);
03abe23b 209 --ssh_entry->ref_count;
83216c72 210 return (void *) -1;
a6df500f 211 }
f449bfef 212 }
a6df500f
CV
213 /* Try allocating memory before calling cygserver. */
214 shm_attached_list *sph_entry = new (shm_attached_list);
215 if (!sph_entry)
1c001dd2 216 {
a6df500f 217 set_errno (ENOMEM);
03abe23b 218 --ssh_entry->ref_count;
83216c72 219 return (void *) -1;
1c001dd2 220 }
1e4e6ee8
CV
221 NTSTATUS status;
222 vm_object_t ptr = NULL;
61522196 223 SIZE_T viewsize = ssh_entry->size;
1e4e6ee8 224 ULONG access = (shmflg & SHM_RDONLY) ? PAGE_READONLY : PAGE_READWRITE;
f16706de 225 status = NtMapViewOfSection (ssh_entry->hdl, NtCurrentProcess (), &ptr, 0,
1e4e6ee8
CV
226 ssh_entry->size, NULL, &viewsize, ViewShare,
227 MEM_TOP_DOWN, access);
228 if (!NT_SUCCESS (status))
038c71f1 229 {
1e4e6ee8 230 __seterrno_from_nt_status (status);
a6df500f 231 delete sph_entry;
03abe23b 232 --ssh_entry->ref_count;
83216c72 233 return (void *) -1;
038c71f1 234 }
a6df500f
CV
235 /* Use returned ptr address as is, so it's stored using the exact value
236 in cygserver. */
237 client_request_shm request (shmid, ptr, shmflg & ~SHM_RND);
238 if (request.make_request () == -1 || request.ptrval () == NULL)
038c71f1 239 {
6b0d86c5 240 syscall_printf ("-1 [%d] = shmat ()", request.error_code ());
a6df500f
CV
241 UnmapViewOfFile (ptr);
242 delete sph_entry;
243 set_errno (request.error_code ());
03abe23b 244 --ssh_entry->ref_count;
bd0e3521 245 if (request.error_code () == ENOSYS)
e3778517 246 raise (SIGSYS);
83216c72 247 return (void *) -1;
038c71f1 248 }
a6df500f 249 sph_entry->ptr = ptr;
03abe23b 250 sph_entry->parent = ssh_entry;
a6df500f 251 sph_entry->access = access;
03abe23b 252 SLIST_LOCK ();
a6df500f 253 SLIST_INSERT_HEAD (&sph_list, sph_entry, sph_next);
03abe23b 254 SLIST_UNLOCK ();
a6df500f 255 return ptr;
e217832c
CV
256}
257
e217832c 258extern "C" int
a6df500f 259shmctl (int shmid, int cmd, struct shmid_ds *buf)
e217832c 260{
61522196 261 syscall_printf ("shmctl (shmid = %d, cmd = %d, buf = %p)",
a6df500f 262 shmid, cmd, buf);
893ac8e0
CF
263 myfault efault;
264 if (efault.faulted (EFAULT))
265 return -1;
a6df500f
CV
266 client_request_shm request (shmid, cmd, buf);
267 if (request.make_request () == -1 || request.retval () == -1)
268 {
269 syscall_printf ("-1 [%d] = shmctl ()", request.error_code ());
270 set_errno (request.error_code ());
bd0e3521 271 if (request.error_code () == ENOSYS)
e3778517 272 raise (SIGSYS);
a6df500f
CV
273 return -1;
274 }
275 if (cmd == IPC_RMID)
276 {
03abe23b 277 /* Cleanup */
a6df500f 278 shm_shmid_list *ssh_entry, *ssh_next_entry;
03abe23b 279 SLIST_LOCK ();
a6df500f 280 SLIST_FOREACH_SAFE (ssh_entry, &ssh_list, ssh_next, ssh_next_entry)
e3778517 281 {
a6df500f
CV
282 if (ssh_entry->shmid == shmid)
283 {
03abe23b
CV
284 /* Remove this entry from the list and close the handle
285 only if it's not in use anymore. */
286 if (ssh_entry->ref_count <= 0)
92beb463 287 {
03abe23b
CV
288 SLIST_REMOVE (&ssh_list, ssh_entry, shm_shmid_list, ssh_next);
289 CloseHandle (ssh_entry->hdl);
290 delete ssh_entry;
92beb463 291 }
a6df500f
CV
292 break;
293 }
294 }
03abe23b 295 SLIST_UNLOCK ();
a6df500f
CV
296 }
297 return request.retval ();
e217832c
CV
298}
299
e217832c 300extern "C" int
a6df500f 301shmdt (const void *shmaddr)
e217832c 302{
6b0d86c5 303 syscall_printf ("shmdt (shmaddr = %p)", shmaddr);
a6df500f
CV
304 client_request_shm request (shmaddr);
305 if (request.make_request () == -1 || request.retval () == -1)
306 {
6b0d86c5 307 syscall_printf ("-1 [%d] = shmdt ()", request.error_code ());
a6df500f 308 set_errno (request.error_code ());
bd0e3521 309 if (request.error_code () == ENOSYS)
e3778517 310 raise (SIGSYS);
a6df500f
CV
311 return -1;
312 }
313 shm_attached_list *sph_entry, *sph_next_entry;
314 /* Remove map from list... */
03abe23b 315 SLIST_LOCK ();
a6df500f
CV
316 SLIST_FOREACH_SAFE (sph_entry, &sph_list, sph_next, sph_next_entry)
317 {
318 if (sph_entry->ptr == shmaddr)
e3778517 319 {
a6df500f 320 SLIST_REMOVE (&sph_list, sph_entry, shm_attached_list, sph_next);
03abe23b 321 /* ...unmap view... */
a6df500f 322 UnmapViewOfFile (sph_entry->ptr);
03abe23b
CV
323 /* ...and, if this was the last reference to this shared section... */
324 shm_shmid_list *ssh_entry = sph_entry->parent;
325 if (--ssh_entry->ref_count <= 0)
326 {
327 /* ...delete parent entry and close handle. */
328 SLIST_REMOVE (&ssh_list, ssh_entry, shm_shmid_list, ssh_next);
329 CloseHandle (ssh_entry->hdl);
330 delete ssh_entry;
331 }
a6df500f
CV
332 delete sph_entry;
333 break;
334 }
335 }
03abe23b 336 SLIST_UNLOCK ();
a6df500f 337 return request.retval ();
e217832c
CV
338}
339
e217832c 340extern "C" int
a6df500f 341shmget (key_t key, size_t size, int shmflg)
e217832c 342{
61522196 343 syscall_printf ("shmget (key = %U, size = %d, shmflg = %y)",
a6df500f
CV
344 key, size, shmflg);
345 /* Try allocating memory before calling cygserver. */
346 shm_shmid_list *ssh_new_entry = new (shm_shmid_list);
347 if (!ssh_new_entry)
348 {
349 set_errno (ENOMEM);
350 return -1;
351 }
352 client_request_shm request (key, size, shmflg);
353 if (request.make_request () == -1 || request.retval () == -1)
354 {
6b0d86c5 355 syscall_printf ("-1 [%d] = shmget ()", request.error_code ());
a6df500f
CV
356 delete ssh_new_entry;
357 set_errno (request.error_code ());
bd0e3521 358 if (request.error_code () == ENOSYS)
e3778517 359 raise (SIGSYS);
a6df500f
CV
360 return -1;
361 }
362 int shmid = request.retval (); /* Shared mem ID */
363 vm_object_t hdl = request.objval (); /* HANDLE associated with it. */
364 shm_shmid_list *ssh_entry;
03abe23b 365 SLIST_LOCK ();
a6df500f
CV
366 SLIST_FOREACH (ssh_entry, &ssh_list, ssh_next)
367 {
368 if (ssh_entry->shmid == shmid)
e3778517 369 {
a6df500f
CV
370 /* We already maintain an entry for this shmid. That means,
371 the hdl returned by cygserver is a superfluous duplicate
372 of the original hdl maintained by cygserver. We can safely
373 delete it. */
374 CloseHandle (hdl);
375 delete ssh_new_entry;
03abe23b 376 SLIST_UNLOCK ();
a6df500f
CV
377 return shmid;
378 }
379 }
380 /* We arrive here only if shmid is a new one for this process. Add the
381 shmid and hdl value to the list. */
382 ssh_new_entry->shmid = shmid;
383 ssh_new_entry->hdl = hdl;
384 ssh_new_entry->size = size;
03abe23b 385 ssh_new_entry->ref_count = 0;
a6df500f 386 SLIST_INSERT_HEAD (&ssh_list, ssh_new_entry, ssh_next);
03abe23b 387 SLIST_UNLOCK ();
a6df500f 388 return shmid;
e217832c 389}
This page took 0.43186 seconds and 5 git commands to generate.