1 /* shm.cc: XSI IPC interface for Cygwin.
3 Copyright 2003 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
15 #include <sys/types.h>
16 #include <sys/queue.h>
23 #include "cygserver_ipc.h"
24 #include "cygserver_shm.h"
28 * client_request_shm Constructors
31 client_request_shm::client_request_shm (int shmid,
34 : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
36 _parameters.in.shmop = SHMOP_shmat;
37 ipc_set_proc_info (_parameters.in.ipcblk);
39 _parameters.in.atargs.shmid = shmid;
40 _parameters.in.atargs.shmaddr = shmaddr;
41 _parameters.in.atargs.shmflg = shmflg;
43 msglen (sizeof (_parameters.in));
46 client_request_shm::client_request_shm (int shmid,
49 : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
51 _parameters.in.shmop = SHMOP_shmctl;
52 ipc_set_proc_info (_parameters.in.ipcblk);
54 _parameters.in.ctlargs.shmid = shmid;
55 _parameters.in.ctlargs.cmd = cmd;
56 _parameters.in.ctlargs.buf = buf;
58 msglen (sizeof (_parameters.in));
61 client_request_shm::client_request_shm (const void *shmaddr)
62 : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
64 _parameters.in.shmop = SHMOP_shmdt;
65 ipc_set_proc_info (_parameters.in.ipcblk);
67 _parameters.in.dtargs.shmaddr = shmaddr;
69 msglen (sizeof (_parameters.in));
72 client_request_shm::client_request_shm (key_t key,
75 : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
77 _parameters.in.shmop = SHMOP_shmget;
78 ipc_set_proc_info (_parameters.in.ipcblk);
80 _parameters.in.getargs.key = key;
81 _parameters.in.getargs.size = size;
82 _parameters.in.getargs.shmflg = shmflg;
84 msglen (sizeof (_parameters.in));
87 client_request_shm::client_request_shm (proc *p1)
88 : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
90 _parameters.in.shmop = SHMOP_shmfork;
91 ipc_set_proc_info (_parameters.in.ipcblk);
93 _parameters.in.forkargs = *p1;
96 /* List of shmid's with file mapping HANDLE and size, returned by shmget. */
97 struct shm_shmid_list {
98 SLIST_ENTRY (shm_shmid_list) ssh_next;
104 static SLIST_HEAD (, shm_shmid_list) ssh_list;
106 /* List of attached mappings, as returned by shmat. */
107 struct shm_attached_list {
108 SLIST_ENTRY (shm_attached_list) sph_next;
115 static SLIST_HEAD (, shm_attached_list) sph_list;
118 fixup_shms_after_fork ()
120 if (!SLIST_FIRST (&sph_list))
122 pinfo p (myself->ppid);
123 proc parent = { myself->ppid, p->dwProcessId, p->uid, p->gid };
125 client_request_shm request (&parent);
126 if (request.make_request () == -1 || request.retval () == -1)
128 syscall_printf ("-1 [%d] = fixup_shms_after_fork ()", request.error_code ());
129 set_errno (request.error_code ());
132 shm_attached_list *sph_entry;
133 /* Remove map from list... */
134 SLIST_FOREACH (sph_entry, &sph_list, sph_next)
136 vm_object_t ptr = MapViewOfFileEx (sph_entry->hdl, sph_entry->access,
137 0, 0, sph_entry->size, sph_entry->ptr);
138 if (ptr != sph_entry->ptr)
139 api_fatal ("MapViewOfFileEx (%p), %E. Terminating.", sph_entry->ptr);
143 #endif /* USE_SERVER */
146 * XSI shmaphore API. These are exported by the DLL.
150 shmat (int shmid, const void *shmaddr, int shmflg)
153 syscall_printf ("shmat (shmid = %d, shmaddr = %p, shmflg = 0x%x)",
154 shmid, shmaddr, shmflg);
156 shm_shmid_list *ssh_entry;
157 SLIST_FOREACH (ssh_entry, &ssh_list, ssh_next)
159 if (ssh_entry->shmid == shmid)
164 /* The shmid is unknown to this process so far. Try to get it from
165 the server if it exists. Use special internal call to shmget,
166 which interprets the key as a shmid and only returns a valid
167 shmid if one exists. Since shmctl inserts a new entry for this
168 shmid into ssh_list automatically, we just have to go through
169 that list again. If that still fails, well, bad luck. */
170 if (shmid && shmget ((key_t) shmid, 0, IPC_KEY_IS_SHMID) != -1)
172 SLIST_FOREACH (ssh_entry, &ssh_list, ssh_next)
174 if (ssh_entry->shmid == shmid)
185 vm_object_t attach_va = NULL;
188 if (shmflg & SHM_RND)
189 attach_va = (vm_object_t)((vm_offset_t)shmaddr & ~(SHMLBA-1));
191 attach_va = (vm_object_t)shmaddr;
192 /* Don't even bother to call anything if shmaddr is NULL or
194 if (!attach_va || (vm_offset_t)attach_va % SHMLBA)
200 /* Try allocating memory before calling cygserver. */
201 shm_attached_list *sph_entry = new (shm_attached_list);
207 DWORD access = (shmflg & SHM_RDONLY) ? FILE_MAP_READ : FILE_MAP_WRITE;
208 vm_object_t ptr = MapViewOfFileEx (ssh_entry->hdl, access, 0, 0,
209 ssh_entry->size, attach_va);
216 /* Use returned ptr address as is, so it's stored using the exact value
218 client_request_shm request (shmid, ptr, shmflg & ~SHM_RND);
219 if (request.make_request () == -1 || request.ptrval () == NULL)
221 syscall_printf ("-1 [%d] = shmat ()", request.error_code ());
222 UnmapViewOfFile (ptr);
224 set_errno (request.error_code ());
225 if (request.error_code () == ENOSYS)
229 sph_entry->ptr = ptr;
230 sph_entry->hdl = ssh_entry->hdl;
231 sph_entry->size = ssh_entry->size;
232 sph_entry->access = access;
233 SLIST_INSERT_HEAD (&sph_list, sph_entry, sph_next);
243 shmctl (int shmid, int cmd, struct shmid_ds *buf)
246 syscall_printf ("shmctl (shmid = %d, cmd = %d, buf = 0x%x)",
249 if (efault.faulted (EFAULT))
251 client_request_shm request (shmid, cmd, buf);
252 if (request.make_request () == -1 || request.retval () == -1)
254 syscall_printf ("-1 [%d] = shmctl ()", request.error_code ());
255 set_errno (request.error_code ());
256 if (request.error_code () == ENOSYS)
262 /* The process must cleanup its own storage... */
263 shm_shmid_list *ssh_entry, *ssh_next_entry;
264 SLIST_FOREACH_SAFE (ssh_entry, &ssh_list, ssh_next, ssh_next_entry)
266 if (ssh_entry->shmid == shmid)
268 SLIST_REMOVE (&ssh_list, ssh_entry, shm_shmid_list, ssh_next);
269 /* ...and close the handle. */
270 CloseHandle (ssh_entry->hdl);
276 return request.retval ();
285 shmdt (const void *shmaddr)
288 syscall_printf ("shmdt (shmaddr = %p)", shmaddr);
289 client_request_shm request (shmaddr);
290 if (request.make_request () == -1 || request.retval () == -1)
292 syscall_printf ("-1 [%d] = shmdt ()", request.error_code ());
293 set_errno (request.error_code ());
294 if (request.error_code () == ENOSYS)
298 shm_attached_list *sph_entry, *sph_next_entry;
299 /* Remove map from list... */
300 SLIST_FOREACH_SAFE (sph_entry, &sph_list, sph_next, sph_next_entry)
302 if (sph_entry->ptr == shmaddr)
304 SLIST_REMOVE (&sph_list, sph_entry, shm_attached_list, sph_next);
305 /* ...and unmap view. */
306 UnmapViewOfFile (sph_entry->ptr);
311 return request.retval ();
320 shmget (key_t key, size_t size, int shmflg)
323 syscall_printf ("shmget (key = %U, size = %d, shmflg = 0x%x)",
325 /* Try allocating memory before calling cygserver. */
326 shm_shmid_list *ssh_new_entry = new (shm_shmid_list);
332 client_request_shm request (key, size, shmflg);
333 if (request.make_request () == -1 || request.retval () == -1)
335 syscall_printf ("-1 [%d] = shmget ()", request.error_code ());
336 delete ssh_new_entry;
337 set_errno (request.error_code ());
338 if (request.error_code () == ENOSYS)
342 int shmid = request.retval (); /* Shared mem ID */
343 vm_object_t hdl = request.objval (); /* HANDLE associated with it. */
344 shm_shmid_list *ssh_entry;
345 SLIST_FOREACH (ssh_entry, &ssh_list, ssh_next)
347 if (ssh_entry->shmid == shmid)
349 /* We already maintain an entry for this shmid. That means,
350 the hdl returned by cygserver is a superfluous duplicate
351 of the original hdl maintained by cygserver. We can safely
354 delete ssh_new_entry;
358 /* We arrive here only if shmid is a new one for this process. Add the
359 shmid and hdl value to the list. */
360 ssh_new_entry->shmid = shmid;
361 ssh_new_entry->hdl = hdl;
362 ssh_new_entry->size = size;
363 SLIST_INSERT_HEAD (&ssh_list, ssh_new_entry, ssh_next);