Line data Source code
1 : /*
2 : +----------------------------------------------------------------------+
3 : | COLOPL PHP TimeShifter. |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) COLOPL, Inc. |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to the BSD-3-Clause license that is |
8 : | bundled with this package in the file LICENSE. |
9 : +----------------------------------------------------------------------+
10 : | Author: Go Kudo <g-kudo@colopl.co.jp> |
11 : +----------------------------------------------------------------------+
12 : */
13 :
14 : #ifndef PHP_WIN32
15 : # include <errno.h>
16 : # include <fcntl.h>
17 : # include <stdio.h>
18 : # include <unistd.h>
19 : #endif
20 : #include <stdint.h>
21 :
22 : #include "php.h"
23 : #include "shared_memory.h"
24 :
25 : #ifndef PHP_WIN32
26 : # ifdef MAP_ANONYMOUS
27 : # define COLOPL_TS_MAP_ANONYMOUS MAP_ANONYMOUS
28 : # elif defined(MAP_ANON)
29 : # define COLOPL_TS_MAP_ANONYMOUS MAP_ANON
30 : # else
31 : # error "Neither MAP_ANONYMOUS nor MAP_ANON is available"
32 : # endif
33 :
34 11714 : static inline sem_t *sm_semaphore(sm_t *sm)
35 : {
36 : # ifdef __APPLE__
37 : return sm->semaphore;
38 : # else
39 11714 : return &sm->semaphore;
40 : # endif
41 : }
42 : #endif
43 :
44 5857 : static inline bool sm_lock(sm_t *sm)
45 : {
46 : #ifdef PHP_WIN32
47 : DWORD wait_result;
48 :
49 : if (!sm->mutex) {
50 : return false;
51 : }
52 :
53 : wait_result = WaitForSingleObject(sm->mutex, INFINITE);
54 : return wait_result == WAIT_OBJECT_0 || wait_result == WAIT_ABANDONED;
55 : #else
56 5857 : sem_t *semaphore = sm_semaphore(sm);
57 :
58 5857 : if (!semaphore) {
59 0 : return false;
60 : }
61 :
62 5857 : while (sem_wait(semaphore) != 0) {
63 0 : if (errno != EINTR) {
64 0 : return false;
65 : }
66 : }
67 5857 : return true;
68 : #endif
69 : }
70 :
71 5857 : static inline bool sm_unlock(sm_t *sm)
72 : {
73 : #ifdef PHP_WIN32
74 : return sm->mutex && ReleaseMutex(sm->mutex);
75 : #else
76 5857 : sem_t *semaphore = sm_semaphore(sm);
77 :
78 5857 : return semaphore && sem_post(semaphore) == 0;
79 : #endif
80 : }
81 :
82 : #if defined(__APPLE__) && !defined(PHP_WIN32)
83 : static bool sm_init_semaphore(sm_t *sm)
84 : {
85 : static unsigned long semaphore_counter;
86 : unsigned int attempts;
87 :
88 : for (attempts = 0; attempts < 16; attempts++) {
89 : snprintf(
90 : sm->semaphore_name,
91 : sizeof(sm->semaphore_name),
92 : "/cts%05lx%05lx",
93 : (unsigned long) getpid() & 0xfffff,
94 : semaphore_counter++ & 0xfffff
95 : );
96 :
97 : sm->semaphore = sem_open(sm->semaphore_name, O_CREAT | O_EXCL, 0600, 1);
98 : if (sm->semaphore != SEM_FAILED) {
99 : if (sem_unlink(sm->semaphore_name) != 0) {
100 : sem_close(sm->semaphore);
101 : sm->semaphore = NULL;
102 : sm->semaphore_name[0] = '\0';
103 : return false;
104 : }
105 : return true;
106 : }
107 :
108 : if (errno != EEXIST) {
109 : break;
110 : }
111 : }
112 :
113 : sm->semaphore = NULL;
114 : sm->semaphore_name[0] = '\0';
115 : return false;
116 : }
117 : #endif
118 :
119 274 : bool sm_init(sm_t *sm, size_t size)
120 : {
121 274 : memset(sm, 0, sizeof(sm_t));
122 274 : sm->size = size;
123 :
124 : #ifdef PHP_WIN32
125 : sm->mapping = CreateFileMapping(
126 : INVALID_HANDLE_VALUE,
127 : NULL,
128 : PAGE_READWRITE,
129 : (DWORD) (((uint64_t) sm->size) >> 32),
130 : (DWORD) (((uint64_t) sm->size) & 0xffffffff),
131 : NULL
132 : );
133 : if (!sm->mapping) {
134 : return false;
135 : }
136 :
137 : sm->data = MapViewOfFile(sm->mapping, FILE_MAP_ALL_ACCESS, 0, 0, sm->size);
138 : if (!sm->data) {
139 : CloseHandle(sm->mapping);
140 : sm->mapping = NULL;
141 : return false;
142 : }
143 :
144 : sm->mutex = CreateMutex(NULL, FALSE, NULL);
145 : if (!sm->mutex) {
146 : UnmapViewOfFile(sm->data);
147 : CloseHandle(sm->mapping);
148 : sm->data = NULL;
149 : sm->mapping = NULL;
150 : return false;
151 : }
152 : #else
153 274 : sm->data = mmap(NULL, sm->size, PROT_READ | PROT_WRITE, MAP_SHARED | COLOPL_TS_MAP_ANONYMOUS, -1, 0);
154 274 : if (sm->data == MAP_FAILED) {
155 0 : sm->data = NULL;
156 0 : return false;
157 : }
158 :
159 : #ifdef __APPLE__
160 : if (!sm_init_semaphore(sm)) {
161 : munmap(sm->data, sm->size);
162 : sm->data = NULL;
163 : return false;
164 : }
165 : #else
166 274 : if (sem_init(&sm->semaphore, 1, 1) != 0) {
167 0 : munmap(sm->data, sm->size);
168 0 : sm->data = NULL;
169 0 : return false;
170 : }
171 : #endif
172 : #endif
173 :
174 274 : return true;
175 : }
176 :
177 5281 : void sm_read(sm_t *sm, void *dest)
178 : {
179 5281 : if (!sm->data) {
180 0 : memset(dest, 0, sm->size);
181 0 : return;
182 : }
183 :
184 5281 : if (!sm_lock(sm)) {
185 0 : memset(dest, 0, sm->size);
186 0 : return;
187 : }
188 :
189 5281 : memcpy(dest, sm->data, sm->size);
190 :
191 5281 : sm_unlock(sm);
192 : }
193 :
194 576 : bool sm_write(sm_t *sm, void *src)
195 : {
196 576 : if (!sm->data) {
197 0 : return false;
198 : }
199 :
200 576 : if (!sm_lock(sm)) {
201 0 : return false;
202 : }
203 :
204 576 : memcpy(sm->data, src, sm->size);
205 :
206 576 : if (!sm_unlock(sm)) {
207 0 : return false;
208 : }
209 :
210 576 : return true;
211 : }
212 :
213 274 : bool sm_free(sm_t *sm)
214 : {
215 274 : bool result = true;
216 :
217 274 : if (!sm->data) {
218 0 : return false;
219 : }
220 :
221 : #ifdef PHP_WIN32
222 : if (!UnmapViewOfFile(sm->data)) {
223 : result = false;
224 : }
225 : sm->data = NULL;
226 :
227 : if (sm->mapping && !CloseHandle(sm->mapping)) {
228 : result = false;
229 : }
230 : sm->mapping = NULL;
231 :
232 : if (sm->mutex && !CloseHandle(sm->mutex)) {
233 : result = false;
234 : }
235 : sm->mutex = NULL;
236 : #else
237 274 : if (munmap(sm->data, sm->size) != 0) {
238 0 : result = false;
239 : }
240 274 : sm->data = NULL;
241 :
242 : # ifdef __APPLE__
243 : if (sm->semaphore && sem_close(sm->semaphore) != 0) {
244 : result = false;
245 : }
246 : sm->semaphore = NULL;
247 : sm->semaphore_name[0] = '\0';
248 : # else
249 274 : if (sem_destroy(&sm->semaphore) != 0) {
250 0 : result = false;
251 : }
252 : # endif
253 : #endif
254 :
255 274 : return result;
256 : }
|