/src/x265/source/common/ringmem.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /***************************************************************************** |
2 | | * Copyright (C) 2013-2017 MulticoreWare, Inc |
3 | | * |
4 | | * Authors: liwei <liwei@multicorewareinc.com> |
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 2 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, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. |
19 | | * |
20 | | * This program is also available under a commercial proprietary license. |
21 | | * For more information, contact us at license @ x265.com |
22 | | *****************************************************************************/ |
23 | | |
24 | | #include "ringmem.h" |
25 | | |
26 | | #ifndef _WIN32 |
27 | | #include <sys/mman.h> |
28 | | #endif ////< _WIN32 |
29 | | |
30 | | #ifdef _WIN32 |
31 | | #define X265_SHARED_MEM_NAME "Local\\_x265_shr_mem_" |
32 | | #define X265_SEMAPHORE_RINGMEM_WRITER_NAME "_x265_semW_" |
33 | | #define X265_SEMAPHORE_RINGMEM_READER_NAME "_x265_semR_" |
34 | | #else /* POSIX / pthreads */ |
35 | 0 | #define X265_SHARED_MEM_NAME "/tmp/_x265_shr_mem_" |
36 | 0 | #define X265_SEMAPHORE_RINGMEM_WRITER_NAME "/tmp/_x265_semW_" |
37 | 0 | #define X265_SEMAPHORE_RINGMEM_READER_NAME "/tmp/_x265_semR_" |
38 | | #endif |
39 | | |
40 | 0 | #define RINGMEM_ALLIGNMENT 64 |
41 | | |
42 | | namespace X265_NS { |
43 | | RingMem::RingMem() |
44 | 0 | : m_initialized(false) |
45 | 0 | , m_protectRW(false) |
46 | 0 | , m_itemSize(0) |
47 | 0 | , m_itemCnt(0) |
48 | | , m_dataPool(NULL) |
49 | | , m_shrMem(NULL) |
50 | | #ifdef _WIN32 |
51 | | , m_handle(NULL) |
52 | | #else //_WIN32 |
53 | | , m_filepath(NULL) |
54 | | #endif //_WIN32 |
55 | | , m_writeSem(NULL) |
56 | | , m_readSem(NULL) |
57 | 0 | { |
58 | 0 | } |
59 | | |
60 | | |
61 | | RingMem::~RingMem() |
62 | 0 | { |
63 | 0 | } |
64 | | |
65 | 0 | bool RingMem::skipRead(int32_t cnt) { |
66 | 0 | if (!m_initialized) |
67 | 0 | { |
68 | 0 | return false; |
69 | 0 | } |
70 | | |
71 | 0 | if (m_protectRW) |
72 | 0 | { |
73 | 0 | for (int i = 0; i < cnt; i++) |
74 | 0 | { |
75 | 0 | m_readSem->take(); |
76 | 0 | } |
77 | 0 | } |
78 | | |
79 | 0 | ATOMIC_ADD(&m_shrMem->m_read, cnt); |
80 | |
|
81 | 0 | if (m_protectRW) |
82 | 0 | { |
83 | 0 | m_writeSem->give(cnt); |
84 | 0 | } |
85 | |
|
86 | 0 | return true; |
87 | 0 | } |
88 | | |
89 | 0 | bool RingMem::skipWrite(int32_t cnt) { |
90 | 0 | if (!m_initialized) |
91 | 0 | { |
92 | 0 | return false; |
93 | 0 | } |
94 | | |
95 | 0 | if (m_protectRW) |
96 | 0 | { |
97 | 0 | for (int i = 0; i < cnt; i++) |
98 | 0 | { |
99 | 0 | m_writeSem->take(); |
100 | 0 | } |
101 | 0 | } |
102 | |
|
103 | 0 | ATOMIC_ADD(&m_shrMem->m_write, cnt); |
104 | |
|
105 | 0 | if (m_protectRW) |
106 | 0 | { |
107 | 0 | m_readSem->give(cnt); |
108 | 0 | } |
109 | |
|
110 | 0 | return true; |
111 | 0 | } |
112 | | |
113 | | ///< initialize |
114 | | bool RingMem::init(int32_t itemSize, int32_t itemCnt, const char *name, bool protectRW) |
115 | 0 | { |
116 | | ///< check parameters |
117 | 0 | if (itemSize <= 0 || itemCnt <= 0 || NULL == name) |
118 | 0 | { |
119 | | ///< invalid parameters |
120 | 0 | return false; |
121 | 0 | } |
122 | | |
123 | 0 | if (!m_initialized) |
124 | 0 | { |
125 | | ///< formating names |
126 | 0 | char nameBuf[MAX_SHR_NAME_LEN] = { 0 }; |
127 | | |
128 | | ///< shared memory name |
129 | 0 | snprintf(nameBuf, sizeof(nameBuf) - 1, "%s%s", X265_SHARED_MEM_NAME, name); |
130 | | |
131 | | ///< create or open shared memory |
132 | 0 | bool newCreated = false; |
133 | | |
134 | | ///< calculate the size of the shared memory |
135 | 0 | int32_t shrMemSize = (itemSize * itemCnt + sizeof(ShrMemCtrl) + RINGMEM_ALLIGNMENT - 1) & ~(RINGMEM_ALLIGNMENT - 1); |
136 | |
|
137 | | #ifdef _WIN32 |
138 | | HANDLE h = OpenFileMappingA(FILE_MAP_WRITE | FILE_MAP_READ, FALSE, nameBuf); |
139 | | if (!h) |
140 | | { |
141 | | h = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, shrMemSize, nameBuf); |
142 | | |
143 | | if (!h) |
144 | | { |
145 | | return false; |
146 | | } |
147 | | |
148 | | newCreated = true; |
149 | | } |
150 | | |
151 | | void *pool = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, 0); |
152 | | |
153 | | ///< should not close the handle here, otherwise the OpenFileMapping would fail |
154 | | //CloseHandle(h); |
155 | | m_handle = h; |
156 | | |
157 | | if (!pool) |
158 | | { |
159 | | return false; |
160 | | } |
161 | | |
162 | | #else /* POSIX / pthreads */ |
163 | 0 | mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; |
164 | 0 | int flag = O_RDWR; |
165 | 0 | int shrfd = -1; |
166 | 0 | if ((shrfd = open(nameBuf, flag, mode)) < 0) |
167 | 0 | { |
168 | 0 | flag |= O_CREAT; |
169 | | |
170 | 0 | shrfd = open(nameBuf, flag, mode); |
171 | 0 | if (shrfd < 0) |
172 | 0 | { |
173 | 0 | return false; |
174 | 0 | } |
175 | 0 | newCreated = true; |
176 | |
|
177 | 0 | lseek(shrfd, shrMemSize - 1, SEEK_SET); |
178 | |
|
179 | 0 | if (-1 == write(shrfd, "\0", 1)) |
180 | 0 | { |
181 | 0 | close(shrfd); |
182 | 0 | return false; |
183 | 0 | } |
184 | | |
185 | 0 | if (lseek(shrfd, 0, SEEK_END) < shrMemSize) |
186 | 0 | { |
187 | 0 | close(shrfd); |
188 | 0 | return false; |
189 | 0 | } |
190 | 0 | } |
191 | | |
192 | 0 | void *pool = mmap(0, |
193 | 0 | shrMemSize, |
194 | 0 | PROT_READ | PROT_WRITE, |
195 | 0 | MAP_SHARED, |
196 | 0 | shrfd, |
197 | 0 | 0); |
198 | |
|
199 | 0 | close(shrfd); |
200 | 0 | if (pool == MAP_FAILED) |
201 | 0 | { |
202 | 0 | return false; |
203 | 0 | } |
204 | | |
205 | 0 | m_filepath = strdup(nameBuf); |
206 | 0 | #endif ///< _WIN32 |
207 | |
|
208 | 0 | if (newCreated) |
209 | 0 | { |
210 | 0 | memset(pool, 0, shrMemSize); |
211 | 0 | } |
212 | | |
213 | 0 | m_shrMem = reinterpret_cast<ShrMemCtrl *>(pool); |
214 | 0 | m_dataPool = reinterpret_cast<uint8_t *>(pool) + sizeof(ShrMemCtrl); |
215 | 0 | m_itemSize = itemSize; |
216 | 0 | m_itemCnt = itemCnt; |
217 | 0 | m_initialized = true; |
218 | |
|
219 | 0 | if (protectRW) |
220 | 0 | { |
221 | 0 | m_protectRW = true; |
222 | 0 | m_writeSem = new NamedSemaphore(); |
223 | 0 | if (!m_writeSem) |
224 | 0 | { |
225 | 0 | release(); |
226 | 0 | return false; |
227 | 0 | } |
228 | | |
229 | | ///< shared memory name |
230 | 0 | snprintf(nameBuf, sizeof(nameBuf) - 1, "%s%s", X265_SEMAPHORE_RINGMEM_WRITER_NAME, name); |
231 | 0 | if (!m_writeSem->create(nameBuf, m_itemCnt, m_itemCnt)) |
232 | 0 | { |
233 | 0 | release(); |
234 | 0 | return false; |
235 | 0 | } |
236 | | |
237 | 0 | m_readSem = new NamedSemaphore(); |
238 | 0 | if (!m_readSem) |
239 | 0 | { |
240 | 0 | release(); |
241 | 0 | return false; |
242 | 0 | } |
243 | | |
244 | | ///< shared memory name |
245 | 0 | snprintf(nameBuf, sizeof(nameBuf) - 1, "%s%s", X265_SEMAPHORE_RINGMEM_READER_NAME, name); |
246 | 0 | if (!m_readSem->create(nameBuf, 0, m_itemCnt)) |
247 | 0 | { |
248 | 0 | release(); |
249 | 0 | return false; |
250 | 0 | } |
251 | 0 | } |
252 | 0 | } |
253 | | |
254 | 0 | return true; |
255 | 0 | } |
256 | | ///< finalize |
257 | | void RingMem::release() |
258 | 0 | { |
259 | 0 | if (m_initialized) |
260 | 0 | { |
261 | 0 | m_initialized = false; |
262 | |
|
263 | 0 | if (m_shrMem) |
264 | 0 | { |
265 | | #ifdef _WIN32 |
266 | | UnmapViewOfFile(m_shrMem); |
267 | | CloseHandle(m_handle); |
268 | | m_handle = NULL; |
269 | | #else /* POSIX / pthreads */ |
270 | 0 | int32_t shrMemSize = (m_itemSize * m_itemCnt + sizeof(ShrMemCtrl) + RINGMEM_ALLIGNMENT - 1) & (~RINGMEM_ALLIGNMENT - 1); |
271 | 0 | munmap(m_shrMem, shrMemSize); |
272 | 0 | unlink(m_filepath); |
273 | 0 | free(m_filepath); |
274 | 0 | m_filepath = NULL; |
275 | 0 | #endif ///< _WIN32 |
276 | 0 | m_shrMem = NULL; |
277 | 0 | m_dataPool = NULL; |
278 | 0 | m_itemSize = 0; |
279 | 0 | m_itemCnt = 0; |
280 | 0 | } |
281 | | |
282 | 0 | if (m_protectRW) |
283 | 0 | { |
284 | 0 | m_protectRW = false; |
285 | 0 | if (m_writeSem) |
286 | 0 | { |
287 | 0 | m_writeSem->release(); |
288 | |
|
289 | 0 | delete m_writeSem; |
290 | 0 | m_writeSem = NULL; |
291 | 0 | } |
292 | |
|
293 | 0 | if (m_readSem) |
294 | 0 | { |
295 | 0 | m_readSem->release(); |
296 | |
|
297 | 0 | delete m_readSem; |
298 | 0 | m_readSem = NULL; |
299 | 0 | } |
300 | 0 | } |
301 | |
|
302 | 0 | } |
303 | 0 | } |
304 | | |
305 | | ///< data read |
306 | | bool RingMem::readNext(void* dst, fnRWSharedData callback) |
307 | 0 | { |
308 | 0 | if (!m_initialized || !callback || !dst) |
309 | 0 | { |
310 | 0 | return false; |
311 | 0 | } |
312 | | |
313 | 0 | if (m_protectRW) |
314 | 0 | { |
315 | 0 | if (!m_readSem->take()) |
316 | 0 | { |
317 | 0 | return false; |
318 | 0 | } |
319 | 0 | } |
320 | | |
321 | 0 | int32_t index = ATOMIC_ADD(&m_shrMem->m_read, 1) % m_itemCnt; |
322 | 0 | (*callback)(dst, reinterpret_cast<uint8_t *>(m_dataPool) + index * m_itemSize, m_itemSize); |
323 | |
|
324 | 0 | if (m_protectRW) |
325 | 0 | { |
326 | 0 | m_writeSem->give(1); |
327 | 0 | } |
328 | |
|
329 | 0 | return true; |
330 | 0 | } |
331 | | ///< data write |
332 | | bool RingMem::writeData(void *data, fnRWSharedData callback) |
333 | 0 | { |
334 | 0 | if (!m_initialized || !data || !callback) |
335 | 0 | { |
336 | 0 | return false; |
337 | 0 | } |
338 | | |
339 | 0 | if (m_protectRW) |
340 | 0 | { |
341 | 0 | if (!m_writeSem->take()) |
342 | 0 | { |
343 | 0 | return false; |
344 | 0 | } |
345 | 0 | } |
346 | | |
347 | 0 | int32_t index = ATOMIC_ADD(&m_shrMem->m_write, 1) % m_itemCnt; |
348 | 0 | (*callback)(reinterpret_cast<uint8_t *>(m_dataPool) + index * m_itemSize, data, m_itemSize); |
349 | |
|
350 | 0 | if (m_protectRW) |
351 | 0 | { |
352 | 0 | m_readSem->give(1); |
353 | 0 | } |
354 | |
|
355 | 0 | return true; |
356 | 0 | } |
357 | | } |