• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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