1 /*
2  * Copyright (C) by Argonne National Laboratory
3  *     See COPYRIGHT in top-level directory
4  */
5 
6 #include "mpl.h"
7 
8 MPL_SUPPRESS_OSX_HAS_NO_SYMBOLS_WARNING;
9 
10 #ifdef MPL_USE_SYSV_SHM
11 
12 #include <sys/stat.h>
13 #include <sys/ipc.h>
14 #include <sys/shm.h>
15 
16 /* A template function which creates/attaches shm seg handle
17  * to the shared memory. Used by user-exposed functions below
18  */
MPL_shm_seg_create_attach_templ(MPL_shm_hnd_t hnd,intptr_t seg_sz,void ** shm_addr_ptr,int offset,int flag)19 static inline int MPL_shm_seg_create_attach_templ(MPL_shm_hnd_t hnd, intptr_t seg_sz,
20                                                   void **shm_addr_ptr, int offset, int flag)
21 {
22     int rc = MPL_SUCCESS;
23     int lhnd = -1;
24 
25     if (flag & MPLI_SHM_FLAG_SHM_CREATE) {
26         lhnd = shmget(IPC_PRIVATE, seg_sz, IPC_CREAT | S_IRWXU);
27         MPLI_shm_lhnd_set(hnd, lhnd);
28         rc = MPLI_shm_ghnd_alloc(hnd, MPL_MEM_SHM);
29         if (rc) {
30             goto fn_exit;
31         }
32         rc = MPLI_shm_ghnd_set_by_val(hnd, "%d", lhnd);
33         if (rc != MPL_SUCCESS) {
34             goto fn_exit;
35         }
36     } else {
37         /* Open an existing shared memory seg */
38         if (!MPLI_shm_lhnd_is_valid(hnd)) {
39             lhnd = atoi(MPLI_shm_ghnd_get_by_ref(hnd));
40             MPLI_shm_lhnd_set(hnd, lhnd);
41         }
42     }
43 
44     if (flag & MPLI_SHM_FLAG_SHM_ATTACH) {
45         const void *start_addr = NULL;
46 
47         /* Caller ensures that shmaddr must be a page-aligned address
48          * at which the attach occurs. EINVAL error would result if a
49          * mapping already exists in this address range or the address
50          * is not page-aligned. */
51         if (flag & MPLI_SHM_FLAG_FIXED_ADDR)
52             start_addr = (const void *) *shm_addr_ptr;
53 
54         /* Attach to shared mem seg */
55         *shm_addr_ptr = shmat(MPLI_shm_lhnd_get(hnd), start_addr, 0x0);
56         if (*shm_addr_ptr == (void *) -1) {
57             rc = MPL_ERR_SHM_INVAL;
58         }
59     }
60 
61   fn_exit:
62     return rc;
63 }
64 
65 /* Create new SHM segment
66  * hnd : A "init"ed shared memory handle
67  * seg_sz : Size of shared memory segment to be created
68  */
MPL_shm_seg_create(MPL_shm_hnd_t hnd,intptr_t seg_sz)69 int MPL_shm_seg_create(MPL_shm_hnd_t hnd, intptr_t seg_sz)
70 {
71     return MPL_shm_seg_create_attach_templ(hnd, seg_sz, NULL, 0, MPLI_SHM_FLAG_SHM_CREATE);
72 }
73 
74 /* Open an existing SHM segment
75  * hnd : A shm handle with a valid global handle
76  * seg_sz : Size of shared memory segment to open
77  * Currently only using internally within wrapper funcs
78  */
MPL_shm_seg_open(MPL_shm_hnd_t hnd,intptr_t seg_sz)79 int MPL_shm_seg_open(MPL_shm_hnd_t hnd, intptr_t seg_sz)
80 {
81     return MPL_shm_seg_create_attach_templ(hnd, seg_sz, NULL, 0, MPLI_SHM_FLAG_CLR);
82 }
83 
84 /* Create new SHM segment and attach to it
85  * hnd : A "init"ed shared mem handle
86  * seg_sz: Size of shared mem segment
87  * shm_addr_ptr : Pointer to shared memory address to attach
88  *                  the shared mem segment
89  * offset : Offset to attach the shared memory address to
90  */
MPL_shm_seg_create_and_attach(MPL_shm_hnd_t hnd,intptr_t seg_sz,void ** shm_addr_ptr,int offset)91 int MPL_shm_seg_create_and_attach(MPL_shm_hnd_t hnd, intptr_t seg_sz,
92                                   void **shm_addr_ptr, int offset)
93 {
94     return MPL_shm_seg_create_attach_templ(hnd, seg_sz, shm_addr_ptr, offset,
95                                            MPLI_SHM_FLAG_SHM_CREATE | MPLI_SHM_FLAG_SHM_ATTACH);
96 }
97 
98 /* Attach to an existing SHM segment
99  * hnd : A "init"ed shared mem handle
100  * seg_sz: Size of shared mem segment
101  * shm_addr_ptr : Pointer to shared memory address to attach
102  *                  the shared mem segment
103  * offset : Offset to attach the shared memory address to
104  */
MPL_shm_seg_attach(MPL_shm_hnd_t hnd,intptr_t seg_sz,void ** shm_addr_ptr,int offset)105 int MPL_shm_seg_attach(MPL_shm_hnd_t hnd, intptr_t seg_sz, void **shm_addr_ptr, int offset)
106 {
107     return MPL_shm_seg_create_attach_templ(hnd, seg_sz, shm_addr_ptr, offset,
108                                            MPLI_SHM_FLAG_SHM_ATTACH);
109 }
110 
111 /* Create new SHM segment and attach to it with specified starting address
112  * hnd : A "init"ed shared mem handle
113  * seg_sz: Size of shared mem segment
114  * shm_addr_ptr (inout): Pointer to specified starting address, the address cannot be NULL.
115  *                       The actual attached memory address is updated at return.
116  * offset : Offset to attach the shared memory address to
117  */
MPL_shm_fixed_seg_create_and_attach(MPL_shm_hnd_t hnd,intptr_t seg_sz,void ** shm_addr_ptr,int offset)118 int MPL_shm_fixed_seg_create_and_attach(MPL_shm_hnd_t hnd, intptr_t seg_sz,
119                                         void **shm_addr_ptr, int offset)
120 {
121     return MPL_shm_seg_create_attach_templ(hnd, seg_sz, shm_addr_ptr, offset,
122                                            MPLI_SHM_FLAG_SHM_CREATE | MPLI_SHM_FLAG_SHM_ATTACH |
123                                            MPLI_SHM_FLAG_FIXED_ADDR);
124 }
125 
126 /* Attach to an existing SHM segment with specified starting address
127  * hnd : A "init"ed shared mem handle
128  * seg_sz: Size of shared mem segment
129  * shm_addr_ptr (inout): Pointer to specified starting address, the address cannot be NULL.
130  *                       The actual attached memory address is updated at return.
131  * offset : Offset to attach the shared memory address to
132  */
MPL_shm_fixed_seg_attach(MPL_shm_hnd_t hnd,intptr_t seg_sz,void ** shm_addr_ptr,int offset)133 int MPL_shm_fixed_seg_attach(MPL_shm_hnd_t hnd, intptr_t seg_sz, void **shm_addr_ptr, int offset)
134 {
135     return MPL_shm_seg_create_attach_templ(hnd, seg_sz, shm_addr_ptr, offset,
136                                            MPLI_SHM_FLAG_SHM_ATTACH | MPLI_SHM_FLAG_FIXED_ADDR);
137 }
138 
139 /* Detach from an attached SHM segment
140  * hnd : Handle to the shm segment
141  * shm_addr_ptr : Pointer to the shm address to detach
142  * seg_sz : Size of shm segment
143  */
MPL_shm_seg_detach(MPL_shm_hnd_t hnd,void ** shm_addr_ptr,intptr_t seg_sz)144 int MPL_shm_seg_detach(MPL_shm_hnd_t hnd, void **shm_addr_ptr, intptr_t seg_sz)
145 {
146     int rc = -1;
147 
148     rc = shmdt(*shm_addr_ptr);
149     *shm_addr_ptr = NULL;
150 
151     return (rc == 0) ? MPL_SUCCESS : MPL_ERR_SHM_INTERN;
152 }
153 
154 /* Remove a shared memory segment
155  * hnd : Handle to the shared memory segment to be removed
156  */
MPL_shm_seg_remove(MPL_shm_hnd_t hnd)157 int MPL_shm_seg_remove(MPL_shm_hnd_t hnd)
158 {
159     struct shmid_ds ds;
160     int rc = -1;
161 
162     rc = shmctl(MPLI_shm_lhnd_get(hnd), IPC_RMID, &ds);
163 
164     return (rc == 0) ? MPL_SUCCESS : MPL_ERR_SHM_INTERN;
165 }
166 
167 #endif /* MPL_USE_SYSV_SHM */
168