PLplot 5.15.0
Loading...
Searching...
No Matches
wxwidgets_comms.cpp
Go to the documentation of this file.
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.
28PLThreeSemaphores::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.
41void 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
72PLThreeSemaphores::~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.
81void 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
129bool PLThreeSemaphores::isWriteSemaphoreValid()
130{
131 return m_wsem != NULL;
132}
133
134bool PLThreeSemaphores::isReadSemaphoreValid()
135{
136 return m_rsem != NULL;
137}
138
139bool 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
148bool 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.
166bool 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.
201int 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.
219int 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
237void 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
251void 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
265void 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
279void 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
294void 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
309void 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//--------------------------------------------------------------------------
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//--------------------------------------------------------------------------
346PLMemoryMap::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//--------------------------------------------------------------------------
367void 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
450void 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
551void 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//--------------------------------------------------------------------------
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//--------------------------------------------------------------------------
654
655#ifndef PL_WXWIDGETS_IPC3
656
658{
659 m_mutex = NULL;
660 m_haveLock = false;
661}
662
663PLNamedMutex::PLNamedMutex( const char *name, bool aquireOnCreate )
664{
665 m_mutex = NULL;
666 m_haveLock = false;
667 create( name, aquireOnCreate );
668}
669
670void 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
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
696bool 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
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
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
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
745
751
753{
754 return m_mutex != NULL;
755}
756
762#endif //#ifndef PL_WXWIDGETS_IPC3
char * getBuffer()
void create(const char *name, PLINT size, bool mustExist, bool mustNotExist)
PLNamedMutex * m_mutex
void create(const char *name, bool aquireOnCreate=false)
char m_mutexName[251]
#define MIN(a, b)
Definition dsplint.c:29
#define TRUE
Definition plplotP.h:176
#define FALSE
Definition plplotP.h:177
int PLINT
Definition plplot.h:181
static const char * name
Definition tkMain.c:135