1 // Copyright (C) 2015-2017 Phil Rosenberg
2 // Copyright (C) 2017 Alan W. Irwin
3 //
4 // This file is part of PLplot.
5 //
6 // PLplot is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU Library General Public License as published
8 // by the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // PLplot 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 Library General Public License for more details.
15 //
16 // You should have received a copy of the GNU Library General Public License
17 // along with PLplot; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 //
20
21 #include "wxwidgets_comms.h"
22 #include <assert.h>
23
24 #ifdef PL_WXWIDGETS_IPC3
25
26 // Default constructor: Initialize m_wsem, m_rsem, and m_tsem to
27 // NULL to mark those as invalid semaphore locations.
PLThreeSemaphores()28 PLThreeSemaphores::PLThreeSemaphores()
29 {
30 m_wsem = NULL;
31 m_rsem = NULL;
32 m_tsem = NULL;
33 }
34
35 // Named semaphores.
36 // Create three semaphore names from basename, and open and (only
37 // on creation which happens automatically for both the Windows
38 // and POSIX API cases) initialize the corresponding named
39 // semaphores with the read and write semaphores initially blocked
40 // and the transmit semaphore initially unblocked.
initializeToValid(const char * baseName)41 void PLThreeSemaphores::initializeToValid( const char * baseName )
42 {
43 // For POSIX named semaphores, name has to start with "/".
44 // FIXME. Remove following comment if this works for Windows.
45 // Does this leading slash affect the Windows case?
46 strcpy( m_wsemName, "/wsem" );
47 strncpy( m_wsemName + 5, baseName, PL_SEMAPHORE_NAME_LENGTH - 5 );
48 m_wsemName[PL_SEMAPHORE_NAME_LENGTH] = '\0';
49
50 strcpy( m_rsemName, "/rsem" );
51 strncpy( m_rsemName + 5, baseName, PL_SEMAPHORE_NAME_LENGTH - 5 );
52 m_rsemName[PL_SEMAPHORE_NAME_LENGTH] = '\0';
53
54 strcpy( m_tsemName, "/tsem" );
55 strncpy( m_tsemName + 5, baseName, PL_SEMAPHORE_NAME_LENGTH - 5 );
56 m_tsemName[PL_SEMAPHORE_NAME_LENGTH] = '\0';
57
58 #ifdef _WIN32
59 // Windows named semaphores.
60 m_wsem = CreateSemaphoreA( NULL, 0, 1, m_wsemName );
61 m_rsem = CreateSemaphoreA( NULL, 0, 1, m_rsemName );
62 m_tsem = CreateSemaphoreA( NULL, 1, 1, m_tsemName );
63 #else // #ifdef _WIN32
64 // POSIX named semaphores.
65 m_wsem = sem_open( m_wsemName, O_CREAT, S_IRWXU, 0 );
66 m_rsem = sem_open( m_rsemName, O_CREAT, S_IRWXU, 0 );
67 m_tsem = sem_open( m_tsemName, O_CREAT, S_IRWXU, 1 );
68 #endif // #ifdef _WIN32
69 }
70
71 // Only destructor
~PLThreeSemaphores()72 PLThreeSemaphores::~PLThreeSemaphores()
73 {
74 initializeToInvalid();
75 }
76
77 // If the m_wsem, m_rsem, and m_tsem locations are non-NULL
78 // destroy those semaphores. Also, unconditionally set
79 // m_wsem, m_rsem, and m_tsem to NULL to mark those as invalid
80 // semaphore locations.
initializeToInvalid()81 void PLThreeSemaphores::initializeToInvalid()
82 {
83 if ( areSemaphoresValid() )
84 {
85 #ifdef _WIN32
86 // Windows named semaphores.
87 CloseHandle( m_wsem );
88 CloseHandle( m_rsem );
89 CloseHandle( m_tsem );
90
91 #else // #ifdef _WIN32
92 // POSIX named semaphores.
93
94 // sem_unlink calls needed to release shared memory resources
95 // used by named semaphores.
96 sem_close( m_wsem );
97 sem_unlink( m_wsemName );
98
99 sem_close( m_rsem );
100 sem_unlink( m_rsemName );
101
102 sem_close( m_tsem );
103 sem_unlink( m_tsemName );
104
105 #endif // #ifdef _WIN32
106 }
107 m_wsem = NULL;
108 m_rsem = NULL;
109 m_tsem = NULL;
110 }
111
112 // Attempts to test semaphore validity using sem_getvalue on Linux
113 // proved fruitless since as far as I can tell with gdb that function
114 // always returns zero, i.e., always signals success ___so long as its
115 // sem_t * argument points to _any_ non-NULL accessible memory area that is
116 // cast to sem_t *__! And when called with a NULL argument sem_getvalue
117 // segfaults rather than returning with a non-zero value! So Linux
118 // sem_getvalue is pretty crude.
119
120 // So instead of checking the return value of sem_getvalue, we instead
121 // only check whether m_wsem and m_rsem are not NULL (signalling
122 // valid) or NULL (signalling invalid).
123
124 // N.B. the default PLThreeSemaphores constructor sets these locations
125 // to NULL, and the alternative constructor or initializeToValid must
126 // be called with mustExist argument false to change these locations
127 // to valid semaphores that are initially blocked.
128
isWriteSemaphoreValid()129 bool PLThreeSemaphores::isWriteSemaphoreValid()
130 {
131 return m_wsem != NULL;
132 }
133
isReadSemaphoreValid()134 bool PLThreeSemaphores::isReadSemaphoreValid()
135 {
136 return m_rsem != NULL;
137 }
138
isTransmitSemaphoreValid()139 bool PLThreeSemaphores::isTransmitSemaphoreValid()
140 {
141 return m_tsem != NULL;
142 }
143
144 // Return true if all semaphores are valid.
145 // Return false if all semaphores are invalid.
146 // Throw an exception otherwise.
147
areSemaphoresValid()148 bool PLThreeSemaphores::areSemaphoresValid()
149 {
150 if ( isWriteSemaphoreValid() && isReadSemaphoreValid() && isTransmitSemaphoreValid() )
151 {
152 return true;
153 }
154 else if ( !isWriteSemaphoreValid() && !isReadSemaphoreValid() && !isTransmitSemaphoreValid() )
155 {
156 return false;
157 }
158
159 throw( "PLThreeSemaphores::areSemaphoresValid: invalid combination of read, write, and transmit semaphore validity" );
160
161 // Should never reach this statement, but include it anyway to quiet possible compiler warnings.
162 return false;
163 }
164
165 // Check whether write and read semaphores are valid and blocked.
areWriteReadSemaphoresBlocked()166 bool PLThreeSemaphores::areWriteReadSemaphoresBlocked()
167 {
168 if ( areSemaphoresValid() )
169 {
170 #ifdef _WIN32
171 // There is no non-destructive way to get the value of Windows named semaphores
172 // so return true when the semaphores are all valid on the assumption that
173 // the write and read semaphore values are zero, i.e., correctly blocked.
174 return true;
175 #else // #ifdef _WIN32
176 int wvalue, rvalue;
177 // We want to test that these are semaphore locations that
178 // have already been properly initialized in blocked state as above.
179 // Attempt to test that assumption with sem_getvalue, but I
180 // have gdb evidence that at least one OS implementation (that on Linux)
181 // of sem_getvalue does not check that the given location is
182 // a valid semaphore, and it is fairly likely in that case that
183 // you will return a value of 0 so this test is not as rigourous as
184 // it should be.
185 if ( sem_getvalue( m_wsem, &wvalue ) != 0 || sem_getvalue( m_rsem, &rvalue ) != 0 )
186 throw( "PLThreeSemaphores::areSemaphoresBlocked: sem_getvalue error on one of the write or read semaphores" );
187 if ( wvalue == 0 && rvalue == 0 )
188 return true;
189 else
190 return false;
191 #endif // #ifdef _WIN32
192 }
193 else
194 {
195 return false;
196 }
197 }
198
199 #ifndef _WIN32
200 // Get value of Write semaphore.
getValueWriteSemaphore()201 int PLThreeSemaphores::getValueWriteSemaphore()
202 {
203 // Initialize to wacko value to quiet compiler uninitialized complaints
204 // for the case of the throws below.
205 int ret_value = -42;
206 if ( !isWriteSemaphoreValid() )
207 {
208 throw( "PLThreeSemaphores::getValueWriteSemaphore: attempt to get value for invalid semaphore." );
209 }
210 else
211 {
212 if ( sem_getvalue( m_wsem, &ret_value ) != 0 )
213 throw( "PLThreeSemaphores::getValueWriteSemaphore: sem_getvalue failed" );
214 }
215 return ret_value;
216 }
217
218 // Get value of Read semaphore.
getValueReadSemaphore()219 int PLThreeSemaphores::getValueReadSemaphore()
220 {
221 // Initialize to wacko value to quiet compiler uninitialized complaints
222 // for the case of the throws below.
223 int ret_value = -42;
224 if ( !isReadSemaphoreValid() )
225 {
226 throw( "PLThreeSemaphores::getValueReadSemaphore: attempt to get value for invalid semaphore." );
227 }
228 else
229 {
230 if ( sem_getvalue( m_rsem, &ret_value ) != 0 )
231 throw( "PLThreeSemaphores::getValueReadSemaphore: sem_getvalue failed" );
232 }
233 return ret_value;
234 }
235 #endif // #ifndef _WIN32
236
postWriteSemaphore()237 void PLThreeSemaphores::postWriteSemaphore()
238 {
239 if ( !isWriteSemaphoreValid() )
240 throw( "PLThreeSemaphores::postWriteSemaphore: invalid write semaphore" );
241
242 #ifdef _WIN32
243 if ( !ReleaseSemaphore( m_wsem, 1, NULL ) )
244 throw( "PLThreeSemaphores::postWriteSemaphore: ReleaseSemaphore failed for write semaphore" );
245 #else // #ifdef _WIN32
246 if ( sem_post( m_wsem ) )
247 throw( "PLThreeSemaphores::postWriteSemaphore: sem_post failed for write semaphore" );
248 #endif // #ifdef _WIN32
249 }
250
postReadSemaphore()251 void PLThreeSemaphores::postReadSemaphore()
252 {
253 if ( !isReadSemaphoreValid() )
254 throw( "PLThreeSemaphores::postReadSemaphore: invalid read semaphore" );
255
256 #ifdef _WIN32
257 if ( !ReleaseSemaphore( m_rsem, 1, NULL ) )
258 throw( "PLThreeSemaphores::postReadSemaphore: ReleaseSemaphore failed for read semaphore" );
259 #else // #ifdef _WIN32
260 if ( sem_post( m_rsem ) )
261 throw( "PLThreeSemaphores::postReadSemaphore: sem_post failed for read semaphore" );
262 #endif // #ifdef _WIN32
263 }
264
postTransmitSemaphore()265 void PLThreeSemaphores::postTransmitSemaphore()
266 {
267 if ( !isTransmitSemaphoreValid() )
268 throw( "PLThreeSemaphores::postTransmitSemaphore: invalid transmit semaphore" );
269
270 #ifdef _WIN32
271 if ( !ReleaseSemaphore( m_tsem, 1, NULL ) )
272 throw( "PLThreeSemaphores::postTransmitSemaphore: ReleaseSemaphore failed for transmit semaphore" );
273 #else // #ifdef _WIN32
274 if ( sem_post( m_tsem ) )
275 throw( "PLThreeSemaphores::postTransmitSemaphore: sem_post failed for transmit semaphore" );
276 #endif // #ifdef _WIN32
277 }
278
waitWriteSemaphore()279 void PLThreeSemaphores::waitWriteSemaphore()
280 {
281 if ( !isWriteSemaphoreValid() )
282 throw( "PLThreeSemaphores::waitWriteSemaphore: invalid write semaphore" );
283
284 #ifdef _WIN32
285 DWORD result = WaitForSingleObject( m_wsem, INFINITE );
286 if ( result == WAIT_FAILED )
287 throw( "PLThreeSemaphores::waitWriteSemaphore: WaitForSingleObject failed for write semaphore" );
288 #else // #ifdef _WIN32
289 if ( sem_wait( m_wsem ) )
290 throw( "PLThreeSemaphores::waitWriteSemaphore: sem_wait failed for write semaphore" );
291 #endif // #ifdef _WIN32
292 }
293
waitReadSemaphore()294 void PLThreeSemaphores::waitReadSemaphore()
295 {
296 if ( !isReadSemaphoreValid() )
297 throw( "PLThreeSemaphores::waitReadSemaphore: invalid read semaphore" );
298
299 #ifdef _WIN32
300 DWORD result = WaitForSingleObject( m_rsem, INFINITE );
301 if ( result == WAIT_FAILED )
302 throw( "PLThreeSemaphores::waitReadSemaphore: WaitForSingleObject failed for read semaphore" );
303 #else // #ifdef _WIN32
304 if ( sem_wait( m_rsem ) )
305 throw( "PLThreeSemaphores::waitReadSemaphore: sem_wait failed for read semaphore" );
306 #endif // #ifdef _WIN32
307 }
308
waitTransmitSemaphore()309 void PLThreeSemaphores::waitTransmitSemaphore()
310 {
311 if ( !isTransmitSemaphoreValid() )
312 throw( "PLThreeSemaphores::waitTransmitSemaphore: invalid transmit semaphore" );
313
314 #ifdef _WIN32
315 DWORD result = WaitForSingleObject( m_tsem, INFINITE );
316 if ( result == WAIT_FAILED )
317 throw( "PLThreeSemaphores::waitTransmitSemaphore: WaitForSingleObject failed for transmit semaphore" );
318 #else // #ifdef _WIN32
319 if ( sem_wait( m_tsem ) )
320 throw( "PLThreeSemaphores::waitTransmitSemaphore: sem_wait failed for transmit semaphore" );
321 #endif // #ifdef _WIN32
322 }
323 #endif //#ifdef PL_WXWIDGETS_IPC3
324
325 //--------------------------------------------------------------------------
326 // Constructor, creates the object but does not actually create or link to
327 // any shared memory.
328 //--------------------------------------------------------------------------
PLMemoryMap()329 PLMemoryMap::PLMemoryMap()
330 {
331 #ifdef _WIN32
332 m_mapFile = NULL;
333 #else
334 m_mapFile = -1;
335 m_name = NULL;
336 #endif
337 m_buffer = NULL;
338 m_size = 0;
339 }
340
341 //--------------------------------------------------------------------------
342 // Constructor, creates the shared memory area. If onlyIfExists is true
343 // then we will try to access an existing shared memory area rather than
344 // creating a new one.
345 //--------------------------------------------------------------------------
PLMemoryMap(const char * name,PLINT size,bool mustExist,bool mustNotExist)346 PLMemoryMap::PLMemoryMap( const char *name, PLINT size, bool mustExist, bool mustNotExist )
347 {
348 #ifdef _WIN32
349 m_mapFile = NULL;
350 #else
351 m_mapFile = -1;
352 m_name = NULL;
353 #endif
354 m_buffer = NULL;
355 m_size = 0;
356 create( name, size, mustExist, mustNotExist );
357 }
358
359 //--------------------------------------------------------------------------
360 // create does most of the work in trying to create the memory map it is
361 // called by the constructor or by the user. If the object already has a
362 // shared memory area then that is closed before a new area of memory is
363 // created or connected to. As per the constructor if onlyIfExists is true
364 // then we will try to access an existing shared memory area rather than
365 // creating a new one.
366 //--------------------------------------------------------------------------
create(const char * name,PLINT size,bool mustExist,bool mustNotExist)367 void PLMemoryMap::create( const char *name, PLINT size, bool mustExist, bool mustNotExist )
368 {
369 close();
370 assert( !( mustExist && mustNotExist ) );
371 if ( mustExist && mustNotExist )
372 return;
373 #ifdef _WIN32
374 if ( mustExist )
375 m_mapFile = OpenFileMappingA( FILE_MAP_ALL_ACCESS, FALSE, name );
376 else if ( mustNotExist )
377 {
378 m_mapFile = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL,
379 PAGE_READWRITE, 0, size, name );
380 if ( GetLastError() == ERROR_ALREADY_EXISTS )
381 close();
382 }
383 else
384 m_mapFile = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL,
385 PAGE_READWRITE, 0, size, name );
386
387 if ( m_mapFile )
388 m_buffer = MapViewOfFile( m_mapFile, FILE_MAP_ALL_ACCESS, 0, 0, size );
389 #else
390 if ( mustExist )
391 {
392 m_mapFile = shm_open( name, O_RDWR, 0 );
393 }
394 else if ( mustNotExist )
395 {
396 m_mapFile = shm_open( name, O_RDWR | O_CREAT | O_EXCL, S_IRWXU ); //S_IRWXU gives user wrx permissions
397 if ( ftruncate( m_mapFile, size ) == -1 )
398 close( );
399 }
400 else
401 {
402 m_mapFile = shm_open( name, O_RDWR | O_CREAT, S_IRWXU ); //S_IRWXU gives user wrx permissions
403 if ( ftruncate( m_mapFile, size ) == -1 )
404 close( );
405 }
406 if ( m_mapFile != -1 )
407 {
408 m_buffer = mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, m_mapFile, 0 );
409 m_name = new char[strlen( name ) + 1];
410 strcpy( m_name, name );
411 }
412 #endif
413 if ( isValid() )
414 m_size = size;
415 }
416
417 #ifdef PL_WXWIDGETS_IPC3
418
419 // This IPC method is an adaptation of the method used in
420 // cmake/test_linux_ipc/pshm_write.c.
421
422 // This transmitBytes method on the transmitting side should be used
423 // in tandem with the receiveBytes method on the receiving side.
424
425 // Transmit data via three-semaphore IPC from the transmitting side to
426 // the receiving side. It is the responsibility of transmitBytes to
427 // check the semaphores are in the correct blocked state at the start
428 // and end of the transmission of data.
429
430 // In the three-semaphores method of IPC, the shared memory area must
431 // correspond to the shmbuf struct which contains some control data
432 // explicitly used for the communication, e.g., at least the total
433 // number of bytes of data to be transferred, and limited size
434 // non-control data areas to be used for transferring an unlimited
435 // number of data bytes.
436
437 // If ifHeader is true, then src is a MemoryMapHeader header
438 // which is transferred to the corresponding area of shared memory
439 // (the internal dest in this case). Otherwise, src is a char array
440 // of unlimited size whose transfer is staged through the data area
441 // (the internal dest in this case) of shared memory.
442
443 // The src argument must always be a pointer to general rather than
444 // shared memory to avoid overlaps between src and internal dest in
445 // shared memory not only for code logic clarity but also because
446 // memcpy rather than memmove is used inside transmitBytes.
447
448 // n is the total number of bytes that will be moved.
449
transmitBytes(bool ifHeader,const void * src,size_t n)450 void PLMemoryMap::transmitBytes( bool ifHeader, const void *src, size_t n )
451 {
452 size_t chunk, nbytes_chunk, transmitted_bytes;
453 const char * csrc = (const char *) src;
454 void * hdest = (void *) getHeader();
455 void * bdest = (void *) getBuffer();
456
457 if ( !isValid() )
458 throw ( "PLMemoryMap::transmitBytes: invalid memory map" );
459
460 size_t size_area;
461 if ( ifHeader )
462 size_area = sizeof ( MemoryMapHeader );
463 else
464 size_area = PL_SHARED_ARRAY_SIZE;
465
466 if ( ifHeader && n != sizeof ( MemoryMapHeader ) )
467 throw( "PLMemoryMap::transmitBytes: ifHeader true has invalid n value" );
468
469 // Wait until previous call (by either side) of transmitBytes has been completed
470 // to avoid a potential race condition.
471 m_threeSemaphores.waitTransmitSemaphore();
472
473 if ( !m_threeSemaphores.areWriteReadSemaphoresBlocked() )
474 throw( "PLMemoryMap::transmitBytes: attempt to start transfer with semaphores not in correct blocked state." );
475 // Receiving side is blocked and initialize this transmitting side to go first.
476 m_threeSemaphores.postWriteSemaphore();
477
478 for ( chunk = 0, transmitted_bytes = 0;; chunk++, csrc += nbytes_chunk )
479 {
480 // Wait for our turn to change the shared memory shmbuf.
481 m_threeSemaphores.waitWriteSemaphore();
482
483 if ( chunk == 0 )
484 {
485 // Update nbytes control data part of that shared memory shmbuf.
486 ( (shmbuf *) m_buffer )->nbytes = n;
487 }
488
489 nbytes_chunk = MIN( size_area, n - transmitted_bytes );
490 if ( nbytes_chunk > 0 )
491 {
492 if ( ifHeader )
493 memcpy( hdest, csrc, nbytes_chunk );
494 else
495 memcpy( bdest, csrc, nbytes_chunk );
496 }
497
498 // Give the receiveBytes method a turn to process the shared
499 // memory shmbuf we have just changed.
500 m_threeSemaphores.postReadSemaphore();
501
502 if ( !( nbytes_chunk > 0 ) )
503 {
504 break;
505 }
506 transmitted_bytes += nbytes_chunk;
507 }
508
509 // All shared memory shmbuf changes have been transmitted so wait
510 // for receiveBytes to process the last of those.
511 m_threeSemaphores.waitWriteSemaphore();
512
513 // If the transfer has been a success, then write and read semaphores should
514 // end up as blocked. Check that:
515 if ( !m_threeSemaphores.areWriteReadSemaphoresBlocked() )
516 throw( "PLMemoryMap::transmitBytes (internal error): transfer finished with write and read semaphores not in correct blocked state." );
517
518 // Allow a subsequent call of transmitBytes (by either side) to start executing.
519 m_threeSemaphores.postTransmitSemaphore();
520 }
521
522 // This IPC method is an adaptation of the method used in
523 // cmake/test_linux_ipc/pshm_read.c.
524
525 // This receiveBytes method on the receiving side should be used in
526 // tandem with the transmitBytes method on the transmitting side.
527
528 // Receive data via three-semaphore IPC from the transmitting side.
529
530 // In the three-semaphores method of IPC, the shared memory area must
531 // correspond to the shmbuf struct which contains some control data
532 // explicitly used for the communication, e.g., at least the total
533 // number of bytes of data to be transferred, and limited size
534 // non-control data areas to be used for transferring an unlimited
535 // number of data bytes.
536
537 // if ifHeader is true, then (the internal) src is the MemoryMapHeader
538 // header area of shared memory which is transferred to a
539 // corresponding area
540 // pointed to by the dest argument. Otherwise, (the internal) src is
541 // the char * data area of shared memory which is a staging area for
542 // the transfer of n bytes into the location pointed to by dest.
543
544 // The dest argument must always be a pointer to general rather than
545 // shared memory to avoid overlaps between internal src in shared
546 // memory and dest not only for code logic clarity but also because
547 // memcpy rather than memmove is used inside receiveBytes.
548
549 // n is the total number of bytes that will be moved.
550
receiveBytes(bool ifHeader,void * dest,size_t n)551 void PLMemoryMap::receiveBytes( bool ifHeader, void *dest, size_t n )
552 {
553 size_t chunk, nbytes, nbytes_chunk, received_bytes;
554 char * cdest = (char *) dest;
555 void * hsrc = (void *) getHeader();
556 void * bsrc = (void *) getBuffer();
557
558 if ( !isValid() )
559 throw( "PLMemoryMap::receiveBytes: invalid memory map" );
560
561 size_t size_area;
562 if ( ifHeader )
563 size_area = sizeof ( MemoryMapHeader );
564 else
565 size_area = PL_SHARED_ARRAY_SIZE;
566
567 if ( ifHeader && n != sizeof ( MemoryMapHeader ) )
568 throw( "PLMemoryMap::receiveBytes: ifHeader true has invalid n value" );
569 // N.B. it is the responsibility of transmitBytes to initialize the semaphores
570 // to the correct values, but we at least check here that the semaphores are valid.
571 m_threeSemaphores.areSemaphoresValid();
572
573 for ( chunk = 0, received_bytes = 0;; chunk++, cdest += nbytes_chunk )
574 {
575 // Wait for our turn to process the shared memory shmbuf that has been updated
576 // by transmitBytes.
577 m_threeSemaphores.waitReadSemaphore();
578
579 if ( chunk == 0 )
580 {
581 // Update *nbytes from the nbytes control data part of that shared memory shmbuf.
582 nbytes = ( (shmbuf *) m_buffer )->nbytes;
583 if ( nbytes > n )
584 throw ( "PLMemoryMap::receiveBytes: n too small to receive results" );
585 }
586
587 nbytes_chunk = MIN( size_area, nbytes - received_bytes );
588 if ( !( nbytes_chunk > 0 ) )
589 {
590 break;
591 }
592 else
593 {
594 received_bytes += nbytes_chunk;
595
596 if ( ifHeader )
597 memcpy( cdest, hsrc, nbytes_chunk );
598 else
599 memcpy( cdest, bsrc, nbytes_chunk );
600 // Give the transmitter a turn to send another chunk of bytes.
601 m_threeSemaphores.postWriteSemaphore();
602 }
603 }
604 // All chunks have been received and processed so signal transmitter
605 // we are done.
606 m_threeSemaphores.postWriteSemaphore();
607
608 // The transmitBytes checks after all transactions with this
609 // receiveBytes routine are completed that the semaphores are in
610 // the correct blocked state. So there is nothing further for us
611 // to check here.
612 }
613 #endif // #ifdef PL_WXWIDGETS_IPC3
614 //--------------------------------------------------------------------------
615 // Close an area of mapped memory. When all processes have closed their
616 // connections the area will be removed by the OS.
617 //--------------------------------------------------------------------------
close()618 void PLMemoryMap::close()
619 {
620 #ifdef _WIN32
621 if ( m_buffer )
622 UnmapViewOfFile( m_buffer );
623 if ( m_mapFile )
624 CloseHandle( m_mapFile );
625 m_mapFile = NULL;
626 #else
627 if ( m_buffer )
628 {
629 munmap( m_buffer, m_size );
630 }
631 if ( m_mapFile != -1 )
632 {
633 shm_unlink( m_name );
634 }
635 if ( m_name )
636 {
637 delete[] m_name;
638 }
639 m_mapFile = -1;
640 m_name = NULL;
641
642 #endif
643 m_buffer = NULL;
644 m_size = 0;
645 }
646
647 //--------------------------------------------------------------------------
648 // Destructor, closes the connection to the mapped memory.
649 //--------------------------------------------------------------------------
~PLMemoryMap()650 PLMemoryMap::~PLMemoryMap()
651 {
652 close();
653 }
654
655 #ifndef PL_WXWIDGETS_IPC3
656
PLNamedMutex()657 PLNamedMutex::PLNamedMutex()
658 {
659 m_mutex = NULL;
660 m_haveLock = false;
661 }
662
PLNamedMutex(const char * name,bool aquireOnCreate)663 PLNamedMutex::PLNamedMutex( const char *name, bool aquireOnCreate )
664 {
665 m_mutex = NULL;
666 m_haveLock = false;
667 create( name, aquireOnCreate );
668 }
669
create(const char * name,bool aquireOnCreate)670 void PLNamedMutex::create( const char *name, bool aquireOnCreate )
671 {
672 #ifdef _WIN32
673 m_mutex = CreateMutexA( NULL, aquireOnCreate ? TRUE : FALSE, name );
674 #else
675 m_mutex = NULL;
676 m_mutexName[0] = '/';
677 strncpy( m_mutexName + 1, name, 250 );
678 m_mutexName[250] = '\0';
679 m_mutex = sem_open( m_mutexName, O_CREAT, S_IRWXU, 1 );
680 #endif
681 }
682
aquire()683 void PLNamedMutex::aquire()
684 {
685 #ifdef _WIN32
686 DWORD result = WaitForSingleObject( m_mutex, INFINITE );
687 m_haveLock = ( result == WAIT_OBJECT_0 || result == WAIT_ABANDONED );
688 #else
689 m_haveLock = sem_wait( m_mutex ) == 0;
690 int result = errno;
691 #endif
692 if ( !m_haveLock )
693 throw( result );
694 }
695
aquire(unsigned long millisecs)696 bool PLNamedMutex::aquire( unsigned long millisecs )
697 {
698 #ifdef _WIN32
699 DWORD result = WaitForSingleObject( m_mutex, millisecs );
700 m_haveLock = ( result == WAIT_OBJECT_0 || result == WAIT_ABANDONED );
701 #else
702 #endif
703 return m_haveLock;
704 }
705
aquireNoWait()706 bool PLNamedMutex::aquireNoWait()
707 {
708 #ifdef _WIN32
709 m_haveLock = ( WAIT_OBJECT_0 == WaitForSingleObject( m_mutex, 0 ) );
710 #else
711 m_haveLock = sem_trywait( m_mutex ) == 0;
712 #endif
713 return m_haveLock;
714 }
715
release()716 void PLNamedMutex::release()
717 {
718 if ( !m_haveLock )
719 return;
720 #ifdef _WIN32
721 if ( m_mutex )
722 ReleaseMutex( m_mutex );
723 #else
724 sem_post( m_mutex );
725 #endif
726 m_haveLock = false;
727 }
728
clear()729 void PLNamedMutex::clear()
730 {
731 release();
732 #ifdef _WIN32
733 CloseHandle( m_mutex );
734 #else
735 sem_close( m_mutex );
736 // Needed to release shared memory resources used by named semaphores.
737 sem_unlink( m_mutexName );
738 #endif
739 }
740
~PLNamedMutex()741 PLNamedMutex::~PLNamedMutex()
742 {
743 clear();
744 }
745
PLNamedMutexLocker(PLNamedMutex * mutex)746 PLNamedMutexLocker::PLNamedMutexLocker( PLNamedMutex *mutex )
747 {
748 m_mutex = mutex;
749 m_mutex->aquire();
750 }
751
isValid()752 bool PLNamedMutex::isValid()
753 {
754 return m_mutex != NULL;
755 }
756
~PLNamedMutexLocker()757 PLNamedMutexLocker::~PLNamedMutexLocker( )
758 {
759 m_mutex->release();
760 m_mutex = NULL;
761 }
762 #endif //#ifndef PL_WXWIDGETS_IPC3
763