PLplot  5.15.0
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.
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.
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
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.
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 
129 bool PLThreeSemaphores::isWriteSemaphoreValid()
130 {
131  return m_wsem != NULL;
132 }
133 
134 bool PLThreeSemaphores::isReadSemaphoreValid()
135 {
136  return m_rsem != NULL;
137 }
138 
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 
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.
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.
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.
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 
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 
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 
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 
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 
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 
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 //--------------------------------------------------------------------------
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 //--------------------------------------------------------------------------
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 //--------------------------------------------------------------------------
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 
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 
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 //--------------------------------------------------------------------------
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 //--------------------------------------------------------------------------
651 {
652  close();
653 }
654 
655 #ifndef PL_WXWIDGETS_IPC3
656 
658 {
659  m_mutex = NULL;
660  m_haveLock = false;
661 }
662 
663 PLNamedMutex::PLNamedMutex( const char *name, bool aquireOnCreate )
664 {
665  m_mutex = NULL;
666  m_haveLock = false;
667  create( name, aquireOnCreate );
668 }
669 
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 
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 
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 
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 
742 {
743  clear();
744 }
745 
747 {
748  m_mutex = mutex;
749  m_mutex->aquire();
750 }
751 
753 {
754  return m_mutex != NULL;
755 }
756 
758 {
759  m_mutex->release();
760  m_mutex = NULL;
761 }
762 #endif //#ifndef PL_WXWIDGETS_IPC3
static const char * name
Definition: tkMain.c:135
char * getBuffer()
int PLINT
Definition: plplot.h:181
#define MIN(a, b)
Definition: dsplint.c:29
void create(const char *name, bool aquireOnCreate=false)
#define TRUE
Definition: plplotP.h:176
#define FALSE
Definition: plplotP.h:177
void create(const char *name, PLINT size, bool mustExist, bool mustNotExist)