Merge branch 'topic/usb-mixer-cache' into next/usb-audio
[linux-2.6] / drivers / staging / epl / ShbIpc-Win32.c
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
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
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
229 tShbError ShbIpcInit(void)
230 {
231
232         return (kShbOk);
233
234 }
235
236 //---------------------------------------------------------------------------
237 //  Deinitialize IPC for Shared Buffer Module
238 //---------------------------------------------------------------------------
239
240 tShbError ShbIpcExit(void)
241 {
242
243         return (kShbOk);
244
245 }
246
247 //---------------------------------------------------------------------------
248 //  Allocate Shared Buffer
249 //---------------------------------------------------------------------------
250
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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