1 /****************************************************************************
2
3 (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
4 www.systec-electronic.com
5
6 Project: Project independend shared buffer (linear + circular)
7
8 Description: Implementation of platform specific part for the
9 shared buffer
10 (Implementation for Win32)
11
12 License:
13
14 Redistribution and use in source and binary forms, with or without
15 modification, are permitted provided that the following conditions
16 are met:
17
18 1. Redistributions of source code must retain the above copyright
19 notice, this list of conditions and the following disclaimer.
20
21 2. Redistributions in binary form must reproduce the above copyright
22 notice, this list of conditions and the following disclaimer in the
23 documentation and/or other materials provided with the distribution.
24
25 3. Neither the name of SYSTEC electronic GmbH nor the names of its
26 contributors may be used to endorse or promote products derived
27 from this software without prior written permission. For written
28 permission, please contact info@systec-electronic.com.
29
30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
33 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
34 COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
35 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
36 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
40 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 POSSIBILITY OF SUCH DAMAGE.
42
43 Severability Clause:
44
45 If a provision of this License is or becomes illegal, invalid or
46 unenforceable in any jurisdiction, that shall not affect:
47 1. the validity or enforceability in that jurisdiction of any other
48 provision of this License; or
49 2. the validity or enforceability in other jurisdictions of that or
50 any other provision of this License.
51
52 -------------------------------------------------------------------------
53
54 2006/06/27 -rs: V 1.00 (initial version)
55
56 ****************************************************************************/
57
58 #define WINVER 0x0400 // #defines necessary for usage of
59 #define _WIN32_WINNT 0x0400 // function <SignalObjectAndWait>
60
61 #include <windows.h>
62 #include <stdio.h>
63 #include "global.h"
64 #include "sharedbuff.h"
65 #include "shbipc.h"
66
67 /***************************************************************************/
68 /* */
69 /* */
70 /* G L O B A L D E F I N I T I O N S */
71 /* */
72 /* */
73 /***************************************************************************/
74
75 #if (!defined(SHBIPC_INLINED)) || defined(SHBIPC_INLINE_ENABLED)
76
77 //---------------------------------------------------------------------------
78 // Configuration
79 //---------------------------------------------------------------------------
80
81 //---------------------------------------------------------------------------
82 // Constant definitions
83 //---------------------------------------------------------------------------
84
85 #define MAX_LEN_BUFFER_ID MAX_PATH
86
87 #define IDX_EVENT_NEW_DATA 0
88 #define IDX_EVENT_TERM_REQU 1
89 #define IDX_EVENT_TERM_RESP 2
90
91 #define NAME_MUTEX_BUFF_ACCESS "BuffAccess"
92 #define NAME_EVENT_NEW_DATA "NewData"
93 #define NAME_EVENT_TERM_REQU "TermRequ"
94 #define NAME_EVENT_TERM_RESP "TermResp"
95 #define NAME_EVENT_JOB_READY "JobReady"
96
97 #define TIMEOUT_ENTER_ATOMIC 1000 // for debgging: INFINITE
98 #define TIMEOUT_TERM_THREAD 2000
99
100 #define SBI_MAGIC_ID 0x5342492B // magic ID ("SBI+")
101 #define SBH_MAGIC_ID 0x5342482A // magic ID ("SBH*")
102
103 //---------------------------------------------------------------------------
104 // Local types
105 //---------------------------------------------------------------------------
106
107 // This structure is the common header for the shared memory region used
108 // by all processes attached this shared memory. It includes common
109 // information to administrate/manage the shared buffer from a couple of
110 // separated processes (e.g. the refernce counter). This structure is
111 // located at the start of the shared memory region itself and exists
112 // consequently only one times per shared memory instance.
113 typedef struct {
114 unsigned long m_SbhMagicID; // magic ID ("SBH*")
115 unsigned long m_ulShMemSize;
116 unsigned long m_ulRefCount;
117 char m_szBufferID[MAX_LEN_BUFFER_ID];
118
119 #ifndef NDEBUG
120 unsigned long m_ulOwnerProcID;
121 #endif
122
123 } tShbMemHeader;
124
125 // This structure is the "external entry point" from a separate process
126 // to get access to a shared buffer. This structure includes all platform
127 // resp. target specific information to administrate/manage the shared
128 // buffer from a separate process. Every process attached to the shared
129 // buffer has its own runtime instance of this structure with its individual
130 // runtime data (e.g. the scope of an event handle is limitted to the
131 // owner process only). The structure member <m_pShbMemHeader> points
132 // to the (process specific) start address of the shared memory region
133 // itself.
134 typedef struct {
135 unsigned long m_SbiMagicID; // magic ID ("SBI+")
136 HANDLE m_hSharedMem;
137 HANDLE m_hMutexBuffAccess;
138 HANDLE m_hThreadNewData; // thraed to signal that new data are available
139 HANDLE m_ahEventNewData[3]; // IDX_EVENT_NEW_DATA + IDX_EVENT_TERM_REQU + ID_EVENT_TERM_RESP
140 tSigHndlrNewData m_pfnSigHndlrNewData;
141 HANDLE m_hThreadJobReady; // thread to signal that a job/operation is ready now (e.g. reset buffer)
142 HANDLE m_hEventJobReady;
143 unsigned long m_ulTimeOutJobReady;
144 tSigHndlrJobReady m_pfnSigHndlrJobReady;
145 tShbMemHeader *m_pShbMemHeader;
146
147 #ifndef NDEBUG
148 unsigned long m_ulThreadIDNewData;
149 unsigned long m_ulThreadIDJobReady;
150 #endif
151
152 } tShbMemInst;
153
154 //---------------------------------------------------------------------------
155 // Global variables
156 //---------------------------------------------------------------------------
157
158 //---------------------------------------------------------------------------
159 // Local variables
160 //---------------------------------------------------------------------------
161
162 //---------------------------------------------------------------------------
163 // Prototypes of internal functions
164 //---------------------------------------------------------------------------
165
166 //---------------------------------------------------------------------------
167 // Get pointer to process local information structure
168 //---------------------------------------------------------------------------
169
ShbIpcGetShbMemInst(tShbInstance pShbInstance_p)170 INLINE_FUNCTION tShbMemInst *ShbIpcGetShbMemInst(tShbInstance pShbInstance_p)
171 {
172
173 tShbMemInst *pShbMemInst;
174
175 pShbMemInst = (tShbMemInst *) pShbInstance_p;
176 ASSERT(pShbMemInst->m_SbiMagicID == SBI_MAGIC_ID);
177
178 return (pShbMemInst);
179
180 }
181
182 //---------------------------------------------------------------------------
183 // Get pointer to shared memory header
184 //---------------------------------------------------------------------------
185
ShbIpcGetShbMemHeader(tShbInstance pShbInstance_p)186 INLINE_FUNCTION tShbMemHeader *ShbIpcGetShbMemHeader(tShbInstance
187 pShbInstance_p)
188 {
189
190 tShbMemInst *pShbMemInst;
191 tShbMemHeader *pShbMemHeader;
192
193 pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p);
194 pShbMemHeader = pShbMemInst->m_pShbMemHeader;
195 ASSERT(pShbMemHeader->m_SbhMagicID == SBH_MAGIC_ID);
196
197 return (pShbMemHeader);
198
199 }
200
201 // not inlined internal functions
202 DWORD WINAPI ShbIpcThreadSignalNewData(LPVOID pvThreadParam_p);
203 DWORD WINAPI ShbIpcThreadSignalJobReady(LPVOID pvThreadParam_p);
204 const char *ShbIpcGetUniformObjectName(const char *pszEventJobName_p,
205 const char *pszBufferID_p,
206 BOOL fGlobalObject_p);
207
208 #endif
209
210 #if !defined(SHBIPC_INLINE_ENABLED)
211 // true internal functions (not inlined)
212 static void *ShbIpcAllocPrivateMem(unsigned long ulMemSize_p);
213 static void ShbIpcReleasePrivateMem(void *pMem_p);
214 #endif
215
216 //=========================================================================//
217 // //
218 // P U B L I C F U N C T I O N S //
219 // //
220 //=========================================================================//
221
222 #if !defined(SHBIPC_INLINE_ENABLED)
223 // not inlined external functions
224
225 //---------------------------------------------------------------------------
226 // Initialize IPC for Shared Buffer Module
227 //---------------------------------------------------------------------------
228
ShbIpcInit(void)229 tShbError ShbIpcInit(void)
230 {
231
232 return (kShbOk);
233
234 }
235
236 //---------------------------------------------------------------------------
237 // Deinitialize IPC for Shared Buffer Module
238 //---------------------------------------------------------------------------
239
ShbIpcExit(void)240 tShbError ShbIpcExit(void)
241 {
242
243 return (kShbOk);
244
245 }
246
247 //---------------------------------------------------------------------------
248 // Allocate Shared Buffer
249 //---------------------------------------------------------------------------
250
ShbIpcAllocBuffer(unsigned long ulBufferSize_p,const char * pszBufferID_p,tShbInstance * ppShbInstance_p,unsigned int * pfShbNewCreated_p)251 tShbError ShbIpcAllocBuffer(unsigned long ulBufferSize_p,
252 const char *pszBufferID_p,
253 tShbInstance * ppShbInstance_p,
254 unsigned int *pfShbNewCreated_p)
255 {
256
257 HANDLE hSharedMem;
258 LPVOID pSharedMem;
259 unsigned long ulShMemSize;
260 tShbMemInst *pShbMemInst;
261 tShbMemHeader *pShbMemHeader;
262 tShbInstance pShbInstance;
263 unsigned int fShMemNewCreated;
264 const char *pszObjectName;
265 HANDLE hMutexBuffAccess;
266 HANDLE hEventNewData;
267 HANDLE hEventJobReady;
268 tShbError ShbError;
269
270 ulShMemSize = ulBufferSize_p + sizeof(tShbMemHeader);
271 pSharedMem = NULL;
272 pShbInstance = NULL;
273 fShMemNewCreated = FALSE;
274 ShbError = kShbOk;
275
276 //---------------------------------------------------------------
277 // (1) open an existing or create a new shared memory
278 //---------------------------------------------------------------
279 // try to open an already existing shared memory
280 // (created by an another process)
281 hSharedMem = OpenFileMapping(FILE_MAP_ALL_ACCESS, // DWORD dwDesiredAccess
282 FALSE, // BOOL bInheritHandle
283 pszBufferID_p); // LPCTSTR lpName
284 if (hSharedMem != NULL) {
285 // a shared memory already exists
286 fShMemNewCreated = FALSE;
287 } else {
288 // it seams that this process is the first who wants to use the
289 // shared memory, so it has to create a new shared memory
290 hSharedMem = CreateFileMapping(INVALID_HANDLE_VALUE, // HANDLE hFile
291 NULL, // LPSECURITY_ATTRIBUTES lpAttributes
292 PAGE_READWRITE, // DWORD flProtect
293 0, // DWORD dwMaximumSizeHigh
294 ulShMemSize, // DWORD dwMaximumSizeLow
295 pszBufferID_p); // LPCTSTR lpName
296
297 fShMemNewCreated = TRUE;
298 }
299
300 if (hSharedMem == NULL) {
301 ShbError = kShbOutOfMem;
302 goto Exit;
303 }
304
305 //---------------------------------------------------------------
306 // (2) get the pointer to the shared memory
307 //---------------------------------------------------------------
308 pSharedMem = MapViewOfFile(hSharedMem, // HANDLE hFileMappingObject
309 FILE_MAP_ALL_ACCESS, // DWORD dwDesiredAccess,
310 0, // DWORD dwFileOffsetHigh,
311 0, // DWORD dwFileOffsetLow,
312 ulShMemSize); // SIZE_T dwNumberOfBytesToMap
313
314 if (pSharedMem == NULL) {
315 ShbError = kShbOutOfMem;
316 goto Exit;
317 }
318
319 //---------------------------------------------------------------
320 // (3) setup or update header and management information
321 //---------------------------------------------------------------
322 pShbMemHeader = (tShbMemHeader *) pSharedMem;
323
324 // allocate a memory block from process specific mempool to save
325 // process local information to administrate/manage the shared buffer
326 pShbMemInst =
327 (tShbMemInst *) ShbIpcAllocPrivateMem(sizeof(tShbMemInst));
328 if (pShbMemInst == NULL) {
329 ShbError = kShbOutOfMem;
330 goto Exit;
331 }
332 // reset complete header to default values
333 pShbMemInst->m_SbiMagicID = SBI_MAGIC_ID;
334 pShbMemInst->m_hSharedMem = hSharedMem;
335 pShbMemInst->m_hMutexBuffAccess = INVALID_HANDLE_VALUE;
336 pShbMemInst->m_hThreadNewData = INVALID_HANDLE_VALUE;
337 pShbMemInst->m_ahEventNewData[IDX_EVENT_NEW_DATA] =
338 INVALID_HANDLE_VALUE;
339 pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_REQU] =
340 INVALID_HANDLE_VALUE;
341 pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_RESP] =
342 INVALID_HANDLE_VALUE;
343 pShbMemInst->m_pfnSigHndlrNewData = NULL;
344 pShbMemInst->m_hThreadJobReady = INVALID_HANDLE_VALUE;
345 pShbMemInst->m_hEventJobReady = INVALID_HANDLE_VALUE;
346 pShbMemInst->m_ulTimeOutJobReady = 0;
347 pShbMemInst->m_pfnSigHndlrJobReady = NULL;
348 pShbMemInst->m_pShbMemHeader = pShbMemHeader;
349
350 #ifndef NDEBUG
351 {
352 pShbMemInst->m_ulThreadIDNewData = 0;
353 pShbMemInst->m_ulThreadIDJobReady = 0;
354 }
355 #endif
356
357 // create mutex for buffer access
358 pszObjectName =
359 ShbIpcGetUniformObjectName(NAME_MUTEX_BUFF_ACCESS, pszBufferID_p,
360 TRUE);
361 hMutexBuffAccess = CreateMutex(NULL, // LPSECURITY_ATTRIBUTES lpMutexAttributes
362 FALSE, // BOOL bInitialOwner
363 pszObjectName); // LPCTSTR lpName
364 pShbMemInst->m_hMutexBuffAccess = hMutexBuffAccess;
365 ASSERT(pShbMemInst->m_hMutexBuffAccess != NULL);
366
367 // The EventNewData is used for signaling of new data after a write
368 // operation (SetEvent) as well as for waiting for new data on the
369 // reader side (WaitForMultipleObjects). Because it's not known if
370 // this process will be read or write data, the event will be
371 // always created here.
372 pszObjectName =
373 ShbIpcGetUniformObjectName(NAME_EVENT_NEW_DATA, pszBufferID_p,
374 TRUE);
375 hEventNewData = CreateEvent(NULL, // LPSECURITY_ATTRIBUTES lpEventAttributes
376 FALSE, // BOOL bManualReset
377 FALSE, // BOOL bInitialState
378 pszObjectName); // LPCTSTR lpName
379 pShbMemInst->m_ahEventNewData[IDX_EVENT_NEW_DATA] = hEventNewData;
380 ASSERT(pShbMemInst->m_ahEventNewData[IDX_EVENT_NEW_DATA] != NULL);
381
382 // The EventJobReady is used for signaling that a job is done (SetEvent)
383 // as well as for waiting for finishing of a job (WaitForMultipleObjects).
384 // Because it's not known if this process will signal or wait, the event
385 // will be always created here.
386 pszObjectName =
387 ShbIpcGetUniformObjectName(NAME_EVENT_JOB_READY, pszBufferID_p,
388 TRUE);
389 hEventJobReady = CreateEvent(NULL, // LPSECURITY_ATTRIBUTES lpEventAttributes
390 FALSE, // BOOL bManualReset
391 FALSE, // BOOL bInitialState
392 pszObjectName); // LPCTSTR lpName
393 pShbMemInst->m_hEventJobReady = hEventJobReady;
394 ASSERT(pShbMemInst->m_hEventJobReady != NULL);
395
396 if (fShMemNewCreated) {
397 // this process was the first who wanted to use the shared memory,
398 // so a new shared memory was created
399 // -> setup new header information inside the shared memory region
400 // itself
401 pShbMemHeader->m_SbhMagicID = SBH_MAGIC_ID;
402 pShbMemHeader->m_ulShMemSize = ulShMemSize;
403 pShbMemHeader->m_ulRefCount = 1;
404 strncpy(pShbMemHeader->m_szBufferID, pszBufferID_p,
405 sizeof(pShbMemHeader->m_szBufferID) - 1);
406
407 #ifndef NDEBUG
408 {
409 pShbMemHeader->m_ulOwnerProcID = GetCurrentProcessId();
410 }
411 #endif
412 } else {
413 // any other process has created the shared memory and this
414 // process has only attached to it
415 // -> check and update existing header information inside the
416 // shared memory region itself
417 if (pShbMemHeader->m_ulShMemSize != ulShMemSize) {
418 ShbError = kShbOpenMismatch;
419 goto Exit;
420 }
421 #ifndef NDEBUG
422 {
423 if (strncmp
424 (pShbMemHeader->m_szBufferID, pszBufferID_p,
425 sizeof(pShbMemHeader->m_szBufferID) - 1)) {
426 ShbError = kShbOpenMismatch;
427 goto Exit;
428 }
429 }
430 #endif
431
432 pShbMemHeader->m_ulRefCount++;
433 }
434
435 // set abstarct "handle" for returning to application
436 pShbInstance = (tShbInstance *) pShbMemInst;
437
438 Exit:
439
440 if (ShbError != kShbOk) {
441 if (pShbMemInst != NULL) {
442 ShbIpcReleasePrivateMem(pShbMemInst);
443 }
444 if (pSharedMem != NULL) {
445 UnmapViewOfFile(pSharedMem);
446 }
447 if (hSharedMem != NULL) {
448 CloseHandle(hSharedMem);
449 }
450 }
451
452 *pfShbNewCreated_p = fShMemNewCreated;
453 *ppShbInstance_p = pShbInstance;
454
455 return (ShbError);
456
457 }
458
459 //---------------------------------------------------------------------------
460 // Release Shared Buffer
461 //---------------------------------------------------------------------------
462
ShbIpcReleaseBuffer(tShbInstance pShbInstance_p)463 tShbError ShbIpcReleaseBuffer(tShbInstance pShbInstance_p)
464 {
465
466 tShbMemInst *pShbMemInst;
467 tShbMemHeader *pShbMemHeader;
468 HANDLE hEventNewData;
469 HANDLE hMutexBuffAccess;
470 tShbError ShbError;
471 tShbError ShbError2;
472
473 if (pShbInstance_p == NULL) {
474 return (kShbOk);
475 }
476
477 pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p);
478 pShbMemHeader = ShbIpcGetShbMemHeader(pShbInstance_p);
479
480 if (!--pShbMemHeader->m_ulRefCount) {
481 ShbError = kShbOk;
482 } else {
483 ShbError = kShbMemUsedByOtherProcs;
484 }
485
486 ShbError2 = ShbIpcStopSignalingNewData(pShbInstance_p);
487 hEventNewData = pShbMemInst->m_ahEventNewData[IDX_EVENT_NEW_DATA];
488 if (hEventNewData != INVALID_HANDLE_VALUE) {
489 CloseHandle(hEventNewData);
490 pShbMemInst->m_ahEventNewData[IDX_EVENT_NEW_DATA] =
491 INVALID_HANDLE_VALUE;
492 }
493
494 hMutexBuffAccess = pShbMemInst->m_hMutexBuffAccess;
495 if (hMutexBuffAccess != INVALID_HANDLE_VALUE) {
496 CloseHandle(hMutexBuffAccess);
497 pShbMemInst->m_hMutexBuffAccess = INVALID_HANDLE_VALUE;
498 }
499
500 UnmapViewOfFile(pShbMemHeader);
501 if (pShbMemInst->m_hSharedMem != INVALID_HANDLE_VALUE) {
502 CloseHandle(pShbMemInst->m_hSharedMem);
503 pShbMemInst->m_hSharedMem = INVALID_HANDLE_VALUE;
504 }
505
506 ShbIpcReleasePrivateMem(pShbMemInst);
507
508 if (ShbError == kShbOk) {
509 ShbError = ShbError2;
510 }
511
512 return (ShbError);
513
514 }
515
516 #endif // !defined(SHBIPC_INLINE_ENABLED)
517
518 #if (!defined(SHBIPC_INLINED)) || defined(SHBIPC_INLINE_ENABLED)
519
520 //---------------------------------------------------------------------------
521 // Enter atomic section for Shared Buffer access
522 //---------------------------------------------------------------------------
523
ShbIpcEnterAtomicSection(tShbInstance pShbInstance_p)524 INLINE_FUNCTION tShbError ShbIpcEnterAtomicSection(tShbInstance pShbInstance_p)
525 {
526
527 tShbMemInst *pShbMemInst;
528 HANDLE hMutexBuffAccess;
529 DWORD dwWaitResult;
530 tShbError ShbError;
531
532 if (pShbInstance_p == NULL) {
533 return (kShbInvalidArg);
534 }
535
536 pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p);
537 ShbError = kShbOk;
538
539 hMutexBuffAccess = pShbMemInst->m_hMutexBuffAccess;
540 if (hMutexBuffAccess != INVALID_HANDLE_VALUE) {
541 dwWaitResult =
542 WaitForSingleObject(hMutexBuffAccess, TIMEOUT_ENTER_ATOMIC);
543 switch (dwWaitResult) {
544 case WAIT_OBJECT_0 + 0:
545 {
546 break;
547 }
548
549 case WAIT_TIMEOUT:
550 {
551 TRACE0
552 ("\nShbIpcEnterAtomicSection(): WAIT_TIMEOUT");
553 ASSERT(0);
554 ShbError = kShbBufferInvalid;
555 break;
556 }
557
558 case WAIT_ABANDONED:
559 {
560 TRACE0
561 ("\nShbIpcEnterAtomicSection(): WAIT_ABANDONED");
562 ASSERT(0);
563 ShbError = kShbBufferInvalid;
564 break;
565 }
566
567 case WAIT_FAILED:
568 {
569 TRACE1
570 ("\nShbIpcEnterAtomicSection(): WAIT_FAILED -> LastError=%ld",
571 GetLastError());
572 ASSERT(0);
573 ShbError = kShbBufferInvalid;
574 break;
575 }
576
577 default:
578 {
579 TRACE1
580 ("\nShbIpcEnterAtomicSection(): unknown error -> LastError=%ld",
581 GetLastError());
582 ASSERT(0);
583 ShbError = kShbBufferInvalid;
584 break;
585 }
586 }
587 } else {
588 ShbError = kShbBufferInvalid;
589 }
590
591 return (ShbError);
592
593 }
594
595 //---------------------------------------------------------------------------
596 // Leave atomic section for Shared Buffer access
597 //---------------------------------------------------------------------------
598
ShbIpcLeaveAtomicSection(tShbInstance pShbInstance_p)599 INLINE_FUNCTION tShbError ShbIpcLeaveAtomicSection(tShbInstance pShbInstance_p)
600 {
601
602 tShbMemInst *pShbMemInst;
603 HANDLE hMutexBuffAccess;
604 BOOL fRes;
605 tShbError ShbError;
606
607 if (pShbInstance_p == NULL) {
608 return (kShbInvalidArg);
609 }
610
611 pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p);
612 ShbError = kShbOk;
613
614 hMutexBuffAccess = pShbMemInst->m_hMutexBuffAccess;
615 if (hMutexBuffAccess != INVALID_HANDLE_VALUE) {
616 fRes = ReleaseMutex(hMutexBuffAccess);
617 ASSERT(fRes);
618 } else {
619 ShbError = kShbBufferInvalid;
620 }
621
622 return (ShbError);
623
624 }
625
626 //---------------------------------------------------------------------------
627 // Start signaling of new data (called from reading process)
628 //---------------------------------------------------------------------------
629
ShbIpcStartSignalingNewData(tShbInstance pShbInstance_p,tSigHndlrNewData pfnSignalHandlerNewData_p,tShbPriority ShbPriority_p)630 INLINE_FUNCTION tShbError ShbIpcStartSignalingNewData(tShbInstance
631 pShbInstance_p,
632 tSigHndlrNewData
633 pfnSignalHandlerNewData_p,
634 tShbPriority
635 ShbPriority_p)
636 {
637
638 tShbMemInst *pShbMemInst;
639 tShbMemHeader *pShbMemHeader;
640 const char *pszObjectName;
641 HANDLE hEventTermRequ;
642 HANDLE hEventTermResp;
643 HANDLE hThreadNewData;
644 unsigned long ulThreadIDNewData;
645 tShbError ShbError;
646 int iPriority;
647
648 if ((pShbInstance_p == NULL) || (pfnSignalHandlerNewData_p == NULL)) {
649 return (kShbInvalidArg);
650 }
651
652 pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p);
653 pShbMemHeader = ShbIpcGetShbMemHeader(pShbInstance_p);
654 ShbError = kShbOk;
655
656 if ((pShbMemInst->m_hThreadNewData != INVALID_HANDLE_VALUE) ||
657 (pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_REQU] !=
658 INVALID_HANDLE_VALUE)
659 || (pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_RESP] !=
660 INVALID_HANDLE_VALUE)
661 || (pShbMemInst->m_pfnSigHndlrNewData != NULL)) {
662 ShbError = kShbAlreadySignaling;
663 goto Exit;
664 }
665
666 pShbMemInst->m_pfnSigHndlrNewData = pfnSignalHandlerNewData_p;
667
668 // Because the event <pShbMemInst->m_ahEventNewData[IDX_EVENT_NEW_DATA]>
669 // is used for signaling of new data after a write operation too (using
670 // SetEvent), it is always created here (see <ShbIpcAllocBuffer>).
671
672 pszObjectName =
673 ShbIpcGetUniformObjectName(NAME_EVENT_TERM_REQU,
674 pShbMemHeader->m_szBufferID, FALSE);
675 hEventTermRequ = CreateEvent(NULL, // LPSECURITY_ATTRIBUTES lpEventAttributes
676 FALSE, // BOOL bManualReset
677 FALSE, // BOOL bInitialState
678 pszObjectName); // LPCTSTR lpName
679 pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_REQU] = hEventTermRequ;
680 ASSERT(pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_REQU] != NULL);
681
682 pszObjectName =
683 ShbIpcGetUniformObjectName(NAME_EVENT_TERM_RESP,
684 pShbMemHeader->m_szBufferID, FALSE);
685 hEventTermResp = CreateEvent(NULL, // LPSECURITY_ATTRIBUTES lpEventAttributes
686 FALSE, // BOOL bManualReset
687 FALSE, // BOOL bInitialState
688 pszObjectName); // LPCTSTR lpName
689 pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_RESP] = hEventTermResp;
690 ASSERT(pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_RESP] != NULL);
691
692 hThreadNewData = CreateThread(NULL, // LPSECURITY_ATTRIBUTES lpThreadAttributes
693 0, // SIZE_T dwStackSize
694 ShbIpcThreadSignalNewData, // LPTHREAD_START_ROUTINE lpStartAddress
695 pShbInstance_p, // LPVOID lpParameter
696 0, // DWORD dwCreationFlags
697 &ulThreadIDNewData); // LPDWORD lpThreadId
698
699 switch (ShbPriority_p) {
700 case kShbPriorityLow:
701 iPriority = THREAD_PRIORITY_BELOW_NORMAL;
702 break;
703
704 case kShbPriorityNormal:
705 iPriority = THREAD_PRIORITY_NORMAL;
706 break;
707
708 case kshbPriorityHigh:
709 iPriority = THREAD_PRIORITY_ABOVE_NORMAL;
710 break;
711
712 }
713
714 ASSERT(pShbMemInst->m_hThreadNewData != NULL);
715
716 SetThreadPriority(hThreadNewData, iPriority);
717
718 pShbMemInst->m_hThreadNewData = hThreadNewData;
719
720 #ifndef NDEBUG
721 {
722 pShbMemInst->m_ulThreadIDNewData = ulThreadIDNewData;
723 }
724 #endif
725
726 Exit:
727
728 return (ShbError);
729
730 }
731
732 //---------------------------------------------------------------------------
733 // Stop signaling of new data (called from reading process)
734 //---------------------------------------------------------------------------
735
ShbIpcStopSignalingNewData(tShbInstance pShbInstance_p)736 INLINE_FUNCTION tShbError ShbIpcStopSignalingNewData(tShbInstance
737 pShbInstance_p)
738 {
739
740 tShbMemInst *pShbMemInst;
741 HANDLE hEventTermRequ;
742 HANDLE hEventTermResp;
743 DWORD dwWaitResult;
744
745 if (pShbInstance_p == NULL) {
746 return (kShbInvalidArg);
747 }
748
749 pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p);
750
751 // terminate new data signaling thread
752 // (set event <hEventTermRequ> to wakeup the thread and dispose it
753 // to exit, then wait for confirmation using event <hEventTermResp>)
754 hEventTermRequ = pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_REQU];
755 hEventTermResp = pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_RESP];
756 if ((hEventTermRequ != INVALID_HANDLE_VALUE) &&
757 (hEventTermResp != INVALID_HANDLE_VALUE)) {
758 TRACE0("\nShbIpcStopSignalingNewData(): enter wait state");
759 dwWaitResult = SignalObjectAndWait(hEventTermRequ, // HANDLE hObjectToSignal
760 hEventTermResp, // HANDLE hObjectToWaitOn
761 TIMEOUT_TERM_THREAD, // DWORD dwMilliseconds
762 FALSE); // BOOL bAlertable
763 TRACE0
764 ("\nShbIpcStopSignalingNewData(): wait state leaved: ---> ");
765 switch (dwWaitResult) {
766 case WAIT_OBJECT_0 + 0: // event "new data signaling thread terminated"
767 {
768 TRACE0("Event = WAIT_OBJECT_0+0");
769 break;
770 }
771
772 default:
773 {
774 TRACE0("Unhandled Event");
775 ASSERT(0);
776 break;
777 }
778 }
779 }
780
781 if (pShbMemInst->m_hThreadNewData != INVALID_HANDLE_VALUE) {
782 CloseHandle(pShbMemInst->m_hThreadNewData);
783 pShbMemInst->m_hThreadNewData = INVALID_HANDLE_VALUE;
784 }
785
786 if (pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_REQU] !=
787 INVALID_HANDLE_VALUE) {
788 CloseHandle(pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_REQU]);
789 pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_REQU] =
790 INVALID_HANDLE_VALUE;
791 }
792
793 if (pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_RESP] !=
794 INVALID_HANDLE_VALUE) {
795 CloseHandle(pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_RESP]);
796 pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_RESP] =
797 INVALID_HANDLE_VALUE;
798 }
799
800 pShbMemInst->m_pfnSigHndlrNewData = NULL;
801
802 return (kShbOk);
803
804 }
805
806 //---------------------------------------------------------------------------
807 // Signal new data (called from writing process)
808 //---------------------------------------------------------------------------
809
ShbIpcSignalNewData(tShbInstance pShbInstance_p)810 INLINE_FUNCTION tShbError ShbIpcSignalNewData(tShbInstance pShbInstance_p)
811 {
812
813 tShbMemInst *pShbMemInst;
814 HANDLE hEventNewData;
815 BOOL fRes;
816
817 // TRACE0("\nShbIpcSignalNewData(): enter\n");
818
819 if (pShbInstance_p == NULL) {
820 return (kShbInvalidArg);
821 }
822
823 pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p);
824
825 ASSERT(pShbMemInst->m_ahEventNewData[IDX_EVENT_NEW_DATA] !=
826 INVALID_HANDLE_VALUE);
827 hEventNewData = pShbMemInst->m_ahEventNewData[IDX_EVENT_NEW_DATA];
828 if (hEventNewData != INVALID_HANDLE_VALUE) {
829 fRes = SetEvent(hEventNewData);
830 // TRACE1("\nShbIpcSignalNewData(): EventNewData set (Result=%d)\n", (int)fRes);
831 ASSERT(fRes);
832 }
833 // TRACE0("\nShbIpcSignalNewData(): leave\n");
834 return (kShbOk);
835
836 }
837
838 //---------------------------------------------------------------------------
839 // Start signaling for job ready (called from waiting process)
840 //---------------------------------------------------------------------------
841
ShbIpcStartSignalingJobReady(tShbInstance pShbInstance_p,unsigned long ulTimeOut_p,tSigHndlrJobReady pfnSignalHandlerJobReady_p)842 INLINE_FUNCTION tShbError ShbIpcStartSignalingJobReady(tShbInstance
843 pShbInstance_p,
844 unsigned long
845 ulTimeOut_p,
846 tSigHndlrJobReady
847 pfnSignalHandlerJobReady_p)
848 {
849
850 tShbMemInst *pShbMemInst;
851 tShbMemHeader *pShbMemHeader;
852 HANDLE hThreadJobReady;
853 unsigned long ulThreadIDJobReady;
854 tShbError ShbError;
855
856 if ((pShbInstance_p == NULL) || (pfnSignalHandlerJobReady_p == NULL)) {
857 return (kShbInvalidArg);
858 }
859
860 pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p);
861 pShbMemHeader = ShbIpcGetShbMemHeader(pShbInstance_p);
862 ShbError = kShbOk;
863
864 if ((pShbMemInst->m_hThreadJobReady != INVALID_HANDLE_VALUE) ||
865 (pShbMemInst->m_pfnSigHndlrJobReady != NULL)) {
866 ShbError = kShbAlreadySignaling;
867 goto Exit;
868 }
869
870 pShbMemInst->m_ulTimeOutJobReady = ulTimeOut_p;
871 pShbMemInst->m_pfnSigHndlrJobReady = pfnSignalHandlerJobReady_p;
872
873 // Because the event <pShbMemInst->m_ahEventJobReady> is used for
874 // signaling of a finished job too (using SetEvent), it is always
875 // created here (see <ShbIpcAllocBuffer>).
876
877 hThreadJobReady = CreateThread(NULL, // LPSECURITY_ATTRIBUTES lpThreadAttributes
878 0, // SIZE_T dwStackSize
879 ShbIpcThreadSignalJobReady, // LPTHREAD_START_ROUTINE lpStartAddress
880 pShbInstance_p, // LPVOID lpParameter
881 0, // DWORD dwCreationFlags
882 &ulThreadIDJobReady); // LPDWORD lpThreadId
883
884 pShbMemInst->m_hThreadJobReady = hThreadJobReady;
885 ASSERT(pShbMemInst->m_hThreadJobReady != NULL);
886
887 #ifndef NDEBUG
888 {
889 pShbMemInst->m_ulThreadIDJobReady = ulThreadIDJobReady;
890 }
891 #endif
892
893 Exit:
894
895 return (ShbError);
896
897 }
898
899 //---------------------------------------------------------------------------
900 // Signal job ready (called from executing process)
901 //---------------------------------------------------------------------------
902
ShbIpcSignalJobReady(tShbInstance pShbInstance_p)903 INLINE_FUNCTION tShbError ShbIpcSignalJobReady(tShbInstance pShbInstance_p)
904 {
905
906 tShbMemInst *pShbMemInst;
907 HANDLE hEventJobReady;
908 BOOL fRes;
909
910 // TRACE0("\nShbIpcSignalJobReady(): enter\n");
911
912 if (pShbInstance_p == NULL) {
913 return (kShbInvalidArg);
914 }
915
916 pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p);
917
918 ASSERT(pShbMemInst->m_hEventJobReady != INVALID_HANDLE_VALUE);
919 hEventJobReady = pShbMemInst->m_hEventJobReady;
920 if (hEventJobReady != INVALID_HANDLE_VALUE) {
921 fRes = SetEvent(hEventJobReady);
922 // TRACE1("\nShbIpcSignalJobReady(): EventJobReady set (Result=%d)\n", (int)fRes);
923 ASSERT(fRes);
924 }
925 // TRACE0("\nShbIpcSignalJobReady(): leave\n");
926 return (kShbOk);
927
928 }
929
930 //---------------------------------------------------------------------------
931 // Get pointer to common used share memory area
932 //---------------------------------------------------------------------------
933
ShbIpcGetShMemPtr(tShbInstance pShbInstance_p)934 INLINE_FUNCTION void *ShbIpcGetShMemPtr(tShbInstance pShbInstance_p)
935 {
936
937 tShbMemHeader *pShbMemHeader;
938 void *pShbShMemPtr;
939
940 pShbMemHeader = ShbIpcGetShbMemHeader(pShbInstance_p);
941 if (pShbMemHeader != NULL) {
942 pShbShMemPtr = (BYTE *) pShbMemHeader + sizeof(tShbMemHeader);
943 } else {
944 pShbShMemPtr = NULL;
945 }
946
947 return (pShbShMemPtr);
948
949 }
950
951 #endif
952
953 //=========================================================================//
954 // //
955 // P R I V A T E F U N C T I O N S //
956 // //
957 //=========================================================================//
958
959 #if !defined(SHBIPC_INLINE_ENABLED)
960
961 //---------------------------------------------------------------------------
962 // Allocate a memory block from process specific mempool
963 //---------------------------------------------------------------------------
964
ShbIpcAllocPrivateMem(unsigned long ulMemSize_p)965 static void *ShbIpcAllocPrivateMem(unsigned long ulMemSize_p)
966 {
967
968 HGLOBAL hMem;
969 void *pMem;
970
971 hMem = GlobalAlloc(GMEM_FIXED, ulMemSize_p + sizeof(HGLOBAL));
972 pMem = GlobalLock(hMem);
973 if (pMem != NULL) {
974 *(HGLOBAL *) pMem = hMem;
975 (BYTE *) pMem += sizeof(HGLOBAL);
976 }
977
978 #ifndef NDEBUG
979 {
980 memset(pMem, 0xaa, ulMemSize_p);
981 }
982 #endif
983
984 return (pMem);
985
986 }
987
988 //---------------------------------------------------------------------------
989 // Release a memory block from process specific mempool
990 //---------------------------------------------------------------------------
991
ShbIpcReleasePrivateMem(void * pMem_p)992 static void ShbIpcReleasePrivateMem(void *pMem_p)
993 {
994
995 HGLOBAL hMem;
996
997 if (pMem_p == NULL) {
998 return;
999 }
1000
1001 (BYTE *) pMem_p -= sizeof(HGLOBAL);
1002 hMem = *(HGLOBAL *) pMem_p;
1003
1004 GlobalUnlock(hMem);
1005 GlobalFree(hMem);
1006
1007 return;
1008
1009 }
1010
1011 //---------------------------------------------------------------------------
1012 // Create uniform object name (needed for inter-process communication)
1013 //---------------------------------------------------------------------------
1014
ShbIpcGetUniformObjectName(const char * pszObjectJobName_p,const char * pszBufferID_p,BOOL fGlobalObject_p)1015 const char *ShbIpcGetUniformObjectName(const char *pszObjectJobName_p,
1016 const char *pszBufferID_p,
1017 BOOL fGlobalObject_p)
1018 {
1019
1020 static char szObjectName[MAX_PATH];
1021 char szObjectPrefix[MAX_PATH];
1022
1023 if (fGlobalObject_p) {
1024 strncpy(szObjectPrefix, "Global\\", sizeof(szObjectPrefix));
1025 } else {
1026 _snprintf(szObjectPrefix, sizeof(szObjectPrefix), "PID%08lX_",
1027 (unsigned long)GetCurrentProcessId());
1028 }
1029
1030 _snprintf(szObjectName, sizeof(szObjectName), "%s%s#%s",
1031 szObjectPrefix, pszBufferID_p, pszObjectJobName_p);
1032
1033 return (szObjectName);
1034
1035 }
1036
1037 //---------------------------------------------------------------------------
1038 // Thread for new data signaling
1039 //---------------------------------------------------------------------------
1040
ShbIpcThreadSignalNewData(LPVOID pvThreadParam_p)1041 DWORD WINAPI ShbIpcThreadSignalNewData(LPVOID pvThreadParam_p)
1042 {
1043
1044 tShbInstance pShbInstance;
1045 tShbMemInst *pShbMemInst;
1046 DWORD dwWaitResult;
1047 BOOL fTermRequ;
1048 int fCallAgain;
1049
1050 TRACE1
1051 ("\nShbIpcThreadSignalNewData(): SignalThread started (pShbInstance=0x%08lX)\n",
1052 (DWORD) pvThreadParam_p);
1053
1054 pShbInstance = (tShbMemInst *) pvThreadParam_p;
1055 pShbMemInst = ShbIpcGetShbMemInst(pShbInstance);
1056 fTermRequ = FALSE;
1057
1058 do {
1059 ASSERT((pShbMemInst->m_ahEventNewData[0] !=
1060 INVALID_HANDLE_VALUE)
1061 && (pShbMemInst->m_ahEventNewData[0] != NULL));
1062 ASSERT((pShbMemInst->m_ahEventNewData[1] !=
1063 INVALID_HANDLE_VALUE)
1064 && (pShbMemInst->m_ahEventNewData[1] != NULL));
1065
1066 TRACE0("\nShbIpcThreadSignalNewData(): enter wait state");
1067 dwWaitResult = WaitForMultipleObjects(2, // DWORD nCount
1068 pShbMemInst->m_ahEventNewData, // const HANDLE* lpHandles
1069 FALSE, // BOOL bWaitAll
1070 INFINITE); // DWORD dwMilliseconds
1071 TRACE0
1072 ("\nShbIpcThreadSignalNewData(): wait state leaved: ---> ");
1073 switch (dwWaitResult) {
1074 case WAIT_OBJECT_0 + 0: // event "new data"
1075 {
1076 TRACE0("Event = WAIT_OBJECT_0+0");
1077 if (pShbMemInst->m_pfnSigHndlrNewData != NULL) {
1078 TRACE0
1079 ("\nShbIpcThreadSignalNewData(): calling SignalHandlerNewData");
1080 do {
1081 fCallAgain =
1082 pShbMemInst->
1083 m_pfnSigHndlrNewData
1084 (pShbInstance);
1085 // d.k.: try to run any shared buffer which has higher priority.
1086 // under Windows this is not really necessary because the Windows scheduler
1087 // already preempts tasks with lower priority.
1088 } while (fCallAgain != FALSE);
1089 }
1090 break;
1091 }
1092
1093 case WAIT_OBJECT_0 + 1: // event "terminate"
1094 {
1095 TRACE0("Event = WAIT_OBJECT_0+1");
1096 fTermRequ = TRUE;
1097 break;
1098 }
1099
1100 default:
1101 {
1102 TRACE0("Unhandled Event");
1103 ASSERT(0);
1104 fTermRequ = TRUE;
1105 break;
1106 }
1107 }
1108 }
1109 while (!fTermRequ);
1110
1111 if (pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_RESP] !=
1112 INVALID_HANDLE_VALUE) {
1113 SetEvent(pShbMemInst->m_ahEventNewData[IDX_EVENT_TERM_RESP]);
1114 }
1115
1116 TRACE1
1117 ("\nShbIpcThreadSignalNewData(): SignalThread terminated (pShbInstance=0x%08lX)\n",
1118 (DWORD) pShbInstance);
1119
1120 ExitThread(0);
1121
1122 }
1123
1124 //---------------------------------------------------------------------------
1125 // Thread for new data signaling
1126 //---------------------------------------------------------------------------
1127
ShbIpcThreadSignalJobReady(LPVOID pvThreadParam_p)1128 DWORD WINAPI ShbIpcThreadSignalJobReady(LPVOID pvThreadParam_p)
1129 {
1130
1131 tShbInstance *pShbInstance;
1132 tShbMemInst *pShbMemInst;
1133 DWORD ulTimeOut;
1134 DWORD dwWaitResult;
1135 unsigned int fTimeOut;
1136
1137 TRACE1
1138 ("\nShbIpcThreadSignalJobReady(): SignalThread started (pShbInstance=0x%08lX)\n",
1139 (DWORD) pvThreadParam_p);
1140
1141 pShbInstance = (tShbInstance *) pvThreadParam_p;
1142 pShbMemInst = ShbIpcGetShbMemInst(pShbInstance);
1143 fTimeOut = FALSE;
1144
1145 if (pShbMemInst->m_ulTimeOutJobReady != 0) {
1146 ulTimeOut = pShbMemInst->m_ulTimeOutJobReady;
1147 } else {
1148 ulTimeOut = INFINITE;
1149 }
1150
1151 ASSERT((pShbMemInst->m_hEventJobReady != INVALID_HANDLE_VALUE)
1152 && (pShbMemInst->m_hEventJobReady != NULL));
1153
1154 TRACE0("\nShbIpcThreadSignalJobReady(): enter wait state");
1155 dwWaitResult = WaitForSingleObject(pShbMemInst->m_hEventJobReady, // HANDLE hHandle
1156 ulTimeOut); // DWORD dwMilliseconds
1157 TRACE0("\nShbIpcThreadSignalJobReady(): wait state leaved: ---> ");
1158 switch (dwWaitResult) {
1159 case WAIT_OBJECT_0 + 0: // event "new data"
1160 {
1161 TRACE0("Event = WAIT_OBJECT_0+0");
1162 fTimeOut = FALSE;
1163 break;
1164 }
1165
1166 case WAIT_TIMEOUT:
1167 {
1168 TRACE0("\nEvent = WAIT_TIMEOUT");
1169 fTimeOut = TRUE;
1170 // ASSERT(0);
1171 break;
1172 }
1173
1174 default:
1175 {
1176 TRACE0("Unhandled Event");
1177 fTimeOut = TRUE;
1178 ASSERT(0);
1179 break;
1180 }
1181 }
1182
1183 if (pShbMemInst->m_pfnSigHndlrJobReady != NULL) {
1184 TRACE0
1185 ("\nShbIpcThreadSignalJobReady(): calling SignalHandlerJobReady");
1186 pShbMemInst->m_pfnSigHndlrJobReady(pShbInstance, fTimeOut);
1187 }
1188
1189 pShbMemInst->m_hThreadJobReady = INVALID_HANDLE_VALUE;
1190 pShbMemInst->m_pfnSigHndlrJobReady = NULL;
1191
1192 TRACE1
1193 ("\nShbIpcThreadSignalJobReady(): SignalThread terminated (pShbInstance=0x%08lX)\n",
1194 (DWORD) pShbInstance);
1195
1196 ExitThread(0);
1197
1198 }
1199
1200 #endif
1201
1202 // EOF
1203