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