| /**************************************************************************** |
| |
| (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29 |
| www.systec-electronic.com |
| |
| Project: Project independend shared buffer (linear + circular) |
| |
| Description: Implementation of platform specific part for the |
| shared buffer |
| (Implementation for Linux KernelSpace) |
| |
| License: |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions |
| are met: |
| |
| 1. Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| |
| 2. Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| |
| 3. Neither the name of SYSTEC electronic GmbH nor the names of its |
| contributors may be used to endorse or promote products derived |
| from this software without prior written permission. For written |
| permission, please contact info@systec-electronic.com. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
| ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| POSSIBILITY OF SUCH DAMAGE. |
| |
| Severability Clause: |
| |
| If a provision of this License is or becomes illegal, invalid or |
| unenforceable in any jurisdiction, that shall not affect: |
| 1. the validity or enforceability in that jurisdiction of any other |
| provision of this License; or |
| 2. the validity or enforceability in other jurisdictions of that or |
| any other provision of this License. |
| |
| ------------------------------------------------------------------------- |
| |
| 2006/06/28 -rs: V 1.00 (initial version) |
| |
| ****************************************************************************/ |
| |
| #include "global.h" |
| #include "SharedBuff.h" |
| #include "ShbIpc.h" |
| #include "ShbLinuxKernel.h" |
| #include "Debug.h" |
| |
| #include <linux/string.h> |
| #include <linux/module.h> |
| #include <asm/processor.h> |
| //#include <linux/vmalloc.h> |
| #include <linux/sched.h> |
| #include <linux/param.h> |
| #include <linux/spinlock.h> |
| #include <linux/wait.h> |
| #include <linux/completion.h> |
| |
| /***************************************************************************/ |
| /* */ |
| /* */ |
| /* G L O B A L D E F I N I T I O N S */ |
| /* */ |
| /* */ |
| /***************************************************************************/ |
| |
| #if (!defined(SHBIPC_INLINED)) || defined(SHBIPC_INLINE_ENABLED) |
| |
| //--------------------------------------------------------------------------- |
| // Configuration |
| //--------------------------------------------------------------------------- |
| |
| //--------------------------------------------------------------------------- |
| // Constant definitions |
| //--------------------------------------------------------------------------- |
| |
| #define MAX_LEN_BUFFER_ID 256 |
| |
| #define TIMEOUT_ENTER_ATOMIC 1000 // (ms) for debgging: INFINITE |
| #define TIMEOUT_TERM_THREAD 1000 |
| #define INFINITE 3600 |
| |
| #define SBI_MAGIC_ID 0x5342492B // magic ID ("SBI+") |
| #define SBH_MAGIC_ID 0x5342482A // magic ID ("SBH*") |
| |
| #define INVALID_ID -1 |
| |
| #define TABLE_SIZE 10 |
| |
| //--------------------------------------------------------------------------- |
| // Local types |
| //--------------------------------------------------------------------------- |
| |
| // This structure is the common header for the shared memory region used |
| // by all processes attached this shared memory. It includes common |
| // information to administrate/manage the shared buffer from a couple of |
| // separated processes (e.g. the refernce counter). This structure is |
| // located at the start of the shared memory region itself and exists |
| // consequently only one times per shared memory instance. |
| typedef struct { |
| |
| unsigned long m_ulShMemSize; |
| unsigned long m_ulRefCount; |
| int m_iBufferId; |
| // int m_iUserSpaceMem; //0 for userspace mem !=0 kernelspace mem |
| spinlock_t m_SpinlockBuffAccess; |
| BOOL m_fNewData; |
| BOOL m_fJobReady; |
| wait_queue_head_t m_WaitQueueNewData; |
| wait_queue_head_t m_WaitQueueJobReady; |
| |
| #ifndef NDEBUG |
| unsigned long m_ulOwnerProcID; |
| #endif |
| |
| } tShbMemHeader; |
| |
| // This structure is the "external entry point" from a separate process |
| // to get access to a shared buffer. This structure includes all platform |
| // resp. target specific information to administrate/manage the shared |
| // buffer from a separate process. Every process attached to the shared |
| // buffer has its own runtime instance of this structure with its individual |
| // runtime data (e.g. the scope of an event handle is limitted to the |
| // owner process only). The structure member <m_pShbMemHeader> points |
| // to the (process specific) start address of the shared memory region |
| // itself. |
| typedef struct { |
| unsigned long m_SbiMagicID; // magic ID ("SBI+") |
| // void* m_pSharedMem; |
| int m_tThreadNewDataId; |
| long m_lThreadNewDataNice; // nice value of the new data thread |
| int m_tThreadJobReadyId; |
| unsigned long m_ulFlagsBuffAccess; // d.k. moved from tShbMemHeader, because each |
| // process needs to store the interrupt flags separately |
| tSigHndlrNewData m_pfnSigHndlrNewData; |
| unsigned long m_ulTimeOutJobReady; |
| tSigHndlrJobReady m_pfnSigHndlrJobReady; |
| tShbMemHeader *m_pShbMemHeader; |
| int m_iThreadTermFlag; |
| struct completion m_CompletionNewData; |
| /* |
| struct semaphore *m_pSemBuffAccess; |
| struct semaphore *m_pSemNewData; |
| struct semaphore *m_pSemStopSignalingNewData; |
| struct semaphore *m_pSemJobReady; |
| */ |
| #ifndef NDEBUG |
| unsigned long m_ulThreadIDNewData; |
| unsigned long m_ulThreadIDJobReady; |
| #endif |
| } tShbMemInst; |
| |
| //--------------------------------------------------------------------------- |
| // Prototypes of internal functions |
| //--------------------------------------------------------------------------- |
| |
| //tShbMemInst* ShbIpcGetShbMemInst (tShbInstance pShbInstance_p); |
| //tShbMemHeader* ShbIpcGetShbMemHeader (tShbMemInst* pShbMemInst_p); |
| |
| //--------------------------------------------------------------------------- |
| // Get pointer to process local information structure |
| //--------------------------------------------------------------------------- |
| |
| static inline tShbMemInst *ShbIpcGetShbMemInst(tShbInstance pShbInstance_p) |
| { |
| |
| tShbMemInst *pShbMemInst; |
| |
| pShbMemInst = (tShbMemInst *) pShbInstance_p; |
| |
| return (pShbMemInst); |
| |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Get pointer to shared memory header |
| //--------------------------------------------------------------------------- |
| |
| static inline tShbMemHeader *ShbIpcGetShbMemHeader(tShbMemInst * pShbMemInst_p) |
| { |
| |
| tShbMemHeader *pShbMemHeader; |
| |
| pShbMemHeader = pShbMemInst_p->m_pShbMemHeader; |
| |
| return (pShbMemHeader); |
| |
| } |
| |
| // Get pointer to process local information structure |
| //#define ShbIpcGetShbMemInst(pShbInstance_p) ((tShbMemInst*)pShbInstance_p) |
| |
| // Get pointer to shared memory header |
| //#define ShbIpcGetShbMemHeader(pShbMemInst_p) (pShbMemInst_p->m_pShbMemHeader) |
| |
| // not inlined internal functions |
| int ShbIpcThreadSignalNewData(void *pvThreadParam_p); |
| int ShbIpcThreadSignalJobReady(void *pvThreadParam_p); |
| #endif |
| |
| //--------------------------------------------------------------------------- |
| // modul globale vars |
| //--------------------------------------------------------------------------- |
| |
| #if !defined(SHBIPC_INLINE_ENABLED) |
| struct sShbMemTable *psMemTableElementFirst_g; |
| |
| static void *ShbIpcAllocPrivateMem(unsigned long ulMemSize_p); |
| static int ShbIpcFindListElement(int iBufferId, |
| struct sShbMemTable |
| **ppsReturnMemTableElement); |
| static void ShbIpcAppendListElement(struct sShbMemTable *sNewMemTableElement); |
| static void ShbIpcDeleteListElement(int iBufferId); |
| static void ShbIpcCrc32GenTable(unsigned long aulCrcTable[256]); |
| static unsigned long ShbIpcCrc32GetCrc(const char *pcString, |
| unsigned long aulCrcTable[256]); |
| |
| #endif |
| |
| //=========================================================================// |
| // // |
| // P U B L I C F U N C T I O N S // |
| // // |
| //=========================================================================// |
| |
| #if !defined(SHBIPC_INLINE_ENABLED) |
| // not inlined external functions |
| |
| //--------------------------------------------------------------------------- |
| // Initialize IPC for Shared Buffer Module |
| //--------------------------------------------------------------------------- |
| |
| tShbError ShbIpcInit(void) |
| { |
| psMemTableElementFirst_g = NULL; |
| return (kShbOk); |
| |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Deinitialize IPC for Shared Buffer Module |
| //--------------------------------------------------------------------------- |
| |
| tShbError ShbIpcExit(void) |
| { |
| |
| return (kShbOk); |
| |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Allocate Shared Buffer |
| //--------------------------------------------------------------------------- |
| |
| tShbError ShbIpcAllocBuffer(unsigned long ulBufferSize_p, |
| const char *pszBufferID_p, |
| tShbInstance * ppShbInstance_p, |
| unsigned int *pfShbNewCreated_p) |
| { |
| tShbError ShbError; |
| int iBufferId = 0; |
| unsigned long ulCrc32 = 0; |
| unsigned int uiFirstProcess = 0; |
| unsigned long ulShMemSize; |
| tShbMemHeader *pShbMemHeader; |
| tShbMemInst *pShbMemInst = NULL; |
| tShbInstance pShbInstance; |
| unsigned int fShMemNewCreated = FALSE; |
| void *pSharedMem = NULL; |
| unsigned long aulCrcTable[256]; |
| struct sShbMemTable *psMemTableElement; |
| |
| DEBUG_LVL_29_TRACE0("ShbIpcAllocBuffer \n"); |
| ulShMemSize = ulBufferSize_p + sizeof(tShbMemHeader); |
| |
| //create Buffer ID |
| ShbIpcCrc32GenTable(aulCrcTable); |
| ulCrc32 = ShbIpcCrc32GetCrc(pszBufferID_p, aulCrcTable); |
| iBufferId = ulCrc32; |
| DEBUG_LVL_29_TRACE2 |
| ("ShbIpcAllocBuffer BufferSize:%d sizeof(tShb..):%d\n", |
| ulBufferSize_p, sizeof(tShbMemHeader)); |
| DEBUG_LVL_29_TRACE2("ShbIpcAllocBuffer BufferId:%d MemSize:%d\n", |
| iBufferId, ulShMemSize); |
| //--------------------------------------------------------------- |
| // (1) open an existing or create a new shared memory |
| //--------------------------------------------------------------- |
| //test if buffer already exists |
| if (ShbIpcFindListElement(iBufferId, &psMemTableElement) == 0) { |
| //Buffer already exists |
| fShMemNewCreated = FALSE; |
| pSharedMem = psMemTableElement->m_pBuffer; |
| DEBUG_LVL_29_TRACE1 |
| ("ShbIpcAllocBuffer attach Buffer at:%p Id:%d\n", |
| pSharedMem); |
| uiFirstProcess = 1; |
| } else { |
| //create new Buffer |
| fShMemNewCreated = TRUE; |
| uiFirstProcess = 0; |
| pSharedMem = kmalloc(ulShMemSize, GFP_KERNEL); |
| DEBUG_LVL_29_TRACE2 |
| ("ShbIpcAllocBuffer Create New Buffer at:%p Id:%d\n", |
| pSharedMem, iBufferId); |
| if (pSharedMem == NULL) { |
| //unable to create mem |
| ShbError = kShbOutOfMem; |
| goto Exit; |
| } |
| DEBUG_LVL_29_TRACE0("ShbIpcAllocBuffer create semas\n"); |
| // append Element to Mem Table |
| psMemTableElement = |
| kmalloc(sizeof(struct sShbMemTable), GFP_KERNEL); |
| psMemTableElement->m_iBufferId = iBufferId; |
| psMemTableElement->m_pBuffer = pSharedMem; |
| psMemTableElement->m_psNextMemTableElement = NULL; |
| ShbIpcAppendListElement(psMemTableElement); |
| } |
| |
| DEBUG_LVL_29_TRACE0("ShbIpcAllocBuffer update header\n"); |
| //update header |
| pShbMemHeader = (tShbMemHeader *) pSharedMem; |
| DEBUG_LVL_29_TRACE1 |
| ("ShbIpcAllocBuffer 0 pShbMemHeader->m_ulShMemSize: %d\n", |
| pShbMemHeader->m_ulShMemSize); |
| // allocate a memory block from process specific mempool to save |
| // process local information to administrate/manage the shared buffer |
| DEBUG_LVL_29_TRACE0("ShbIpcAllocBuffer alloc private mem\n"); |
| pShbMemInst = |
| (tShbMemInst *) ShbIpcAllocPrivateMem(sizeof(tShbMemInst)); |
| if (pShbMemInst == NULL) { |
| ShbError = kShbOutOfMem; |
| goto Exit; |
| } |
| // reset complete header to default values |
| //pShbMemInst->m_SbiMagicID = SBI_MAGIC_ID; |
| // pShbMemInst->m_pSharedMem = pSharedMem; |
| pShbMemInst->m_tThreadNewDataId = INVALID_ID; |
| pShbMemInst->m_tThreadJobReadyId = INVALID_ID; |
| pShbMemInst->m_pfnSigHndlrNewData = NULL; |
| pShbMemInst->m_ulTimeOutJobReady = 0; |
| pShbMemInst->m_pfnSigHndlrJobReady = NULL; |
| pShbMemInst->m_pShbMemHeader = pShbMemHeader; |
| pShbMemInst->m_iThreadTermFlag = 0; |
| |
| // initialize completion etc. |
| init_completion(&pShbMemInst->m_CompletionNewData); |
| |
| ShbError = kShbOk; |
| if (fShMemNewCreated) { |
| // this process was the first who wanted to use the shared memory, |
| // so a new shared memory was created |
| // -> setup new header information inside the shared memory region |
| // itself |
| pShbMemHeader->m_ulShMemSize = ulShMemSize; |
| pShbMemHeader->m_ulRefCount = 1; |
| pShbMemHeader->m_iBufferId = iBufferId; |
| // initialize spinlock |
| spin_lock_init(&pShbMemHeader->m_SpinlockBuffAccess); |
| // initialize wait queues |
| init_waitqueue_head(&pShbMemHeader->m_WaitQueueNewData); |
| init_waitqueue_head(&pShbMemHeader->m_WaitQueueJobReady); |
| } else { |
| // any other process has created the shared memory and this |
| // process only has to attach to it |
| // -> check and update existing header information inside the |
| // shared memory region itself |
| if (pShbMemHeader->m_ulShMemSize != ulShMemSize) { |
| ShbError = kShbOpenMismatch; |
| goto Exit; |
| } |
| pShbMemHeader->m_ulRefCount++; |
| } |
| |
| Exit: |
| pShbInstance = (tShbInstance *) pShbMemInst; |
| *pfShbNewCreated_p = fShMemNewCreated; |
| *ppShbInstance_p = pShbInstance; |
| return (ShbError); |
| |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Release Shared Buffer |
| //--------------------------------------------------------------------------- |
| |
| tShbError ShbIpcReleaseBuffer(tShbInstance pShbInstance_p) |
| { |
| tShbMemInst *pShbMemInst; |
| tShbMemHeader *pShbMemHeader; |
| tShbError ShbError; |
| tShbError ShbError2; |
| |
| DEBUG_LVL_26_TRACE1("ShbIpcReleaseBuffer(%p)\n", pShbInstance_p); |
| if (pShbInstance_p == NULL) { |
| return (kShbOk); |
| } |
| pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p); |
| pShbMemHeader = ShbIpcGetShbMemHeader(pShbMemInst); |
| |
| // stop threads in any case, because they are bound to that specific instance |
| ShbError2 = ShbIpcStopSignalingNewData(pShbInstance_p); |
| // d.k.: Whats up with JobReady thread? |
| // Just wake it up, but without setting the semaphore variable |
| wake_up_interruptible(&pShbMemHeader->m_WaitQueueJobReady); |
| |
| if (!--pShbMemHeader->m_ulRefCount) { |
| ShbError = kShbOk; |
| // delete mem table element |
| ShbIpcDeleteListElement(pShbMemHeader->m_iBufferId); |
| // delete shared mem |
| kfree(pShbMemInst->m_pShbMemHeader); |
| } else { |
| ShbError = kShbMemUsedByOtherProcs; |
| } |
| //delete privat mem |
| kfree(pShbMemInst); |
| return (ShbError); |
| } |
| |
| #endif // !defined(SHBIPC_INLINE_ENABLED) |
| |
| #if (!defined(SHBIPC_INLINED)) || defined(SHBIPC_INLINE_ENABLED) |
| |
| //--------------------------------------------------------------------------- |
| // Enter atomic section for Shared Buffer access |
| //--------------------------------------------------------------------------- |
| |
| INLINE_FUNCTION tShbError ShbIpcEnterAtomicSection(tShbInstance pShbInstance_p) |
| { |
| |
| tShbMemInst *pShbMemInst; |
| tShbMemHeader *pShbMemHeader; |
| tShbError ShbError = kShbOk; |
| |
| if (pShbInstance_p == NULL) { |
| ShbError = kShbInvalidArg; |
| goto Exit; |
| } |
| DEBUG_LVL_29_TRACE0("enter atomic\n"); |
| pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p); |
| pShbMemHeader = ShbIpcGetShbMemHeader(pShbMemInst); |
| |
| // lock interrupts |
| spin_lock_irqsave(&pShbMemHeader->m_SpinlockBuffAccess, |
| pShbMemInst->m_ulFlagsBuffAccess); |
| |
| Exit: |
| return ShbError; |
| |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Leave atomic section for Shared Buffer access |
| //--------------------------------------------------------------------------- |
| |
| INLINE_FUNCTION tShbError ShbIpcLeaveAtomicSection(tShbInstance pShbInstance_p) |
| { |
| |
| tShbMemInst *pShbMemInst; |
| tShbMemHeader *pShbMemHeader; |
| tShbError ShbError = kShbOk; |
| |
| if (pShbInstance_p == NULL) { |
| ShbError = kShbInvalidArg; |
| goto Exit; |
| } |
| pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p); |
| pShbMemHeader = ShbIpcGetShbMemHeader(pShbMemInst); |
| // unlock interrupts |
| spin_unlock_irqrestore(&pShbMemHeader->m_SpinlockBuffAccess, |
| pShbMemInst->m_ulFlagsBuffAccess); |
| |
| Exit: |
| DEBUG_LVL_29_TRACE0("Leave Atomic \n"); |
| return ShbError; |
| |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Start signaling of new data (called from reading process) |
| //--------------------------------------------------------------------------- |
| |
| INLINE_FUNCTION tShbError ShbIpcStartSignalingNewData(tShbInstance |
| pShbInstance_p, |
| tSigHndlrNewData |
| pfnSignalHandlerNewData_p, |
| tShbPriority |
| ShbPriority_p) |
| { |
| tShbMemInst *pShbMemInst; |
| tShbMemHeader *pShbMemHeader; |
| tShbError ShbError; |
| |
| DEBUG_LVL_29_TRACE0("------->ShbIpcStartSignalingNewData\n"); |
| if ((pShbInstance_p == NULL) || (pfnSignalHandlerNewData_p == NULL)) { |
| return (kShbInvalidArg); |
| } |
| |
| pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p); |
| pShbMemHeader = ShbIpcGetShbMemHeader(pShbMemInst); |
| ShbError = kShbOk; |
| |
| if ((pShbMemInst->m_tThreadNewDataId != INVALID_ID) |
| || (pShbMemInst->m_pfnSigHndlrNewData != NULL)) { |
| ShbError = kShbAlreadySignaling; |
| goto Exit; |
| } |
| DEBUG_LVL_26_TRACE2 |
| ("ShbIpcStartSignalingNewData(%p) m_pfnSigHndlrNewData = %p\n", |
| pShbInstance_p, pfnSignalHandlerNewData_p); |
| pShbMemInst->m_pfnSigHndlrNewData = pfnSignalHandlerNewData_p; |
| pShbMemHeader->m_fNewData = FALSE; |
| pShbMemInst->m_iThreadTermFlag = 0; |
| |
| switch (ShbPriority_p) { |
| case kShbPriorityLow: |
| pShbMemInst->m_lThreadNewDataNice = -2; |
| break; |
| |
| case kShbPriorityNormal: |
| pShbMemInst->m_lThreadNewDataNice = -9; |
| break; |
| |
| case kshbPriorityHigh: |
| pShbMemInst->m_lThreadNewDataNice = -20; |
| break; |
| |
| } |
| |
| //create thread for signalling new data |
| pShbMemInst->m_tThreadNewDataId = |
| kernel_thread(ShbIpcThreadSignalNewData, pShbInstance_p, |
| CLONE_KERNEL); |
| |
| Exit: |
| return ShbError; |
| |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Stop signaling of new data (called from reading process) |
| //--------------------------------------------------------------------------- |
| |
| INLINE_FUNCTION tShbError ShbIpcStopSignalingNewData(tShbInstance |
| pShbInstance_p) |
| { |
| tShbMemInst *pShbMemInst; |
| tShbMemHeader *pShbMemHeader; |
| tShbError ShbError; |
| |
| DEBUG_LVL_29_TRACE0("------->ShbIpcStopSignalingNewData\n"); |
| if (pShbInstance_p == NULL) { |
| return (kShbInvalidArg); |
| } |
| ShbError = kShbOk; |
| pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p); |
| pShbMemHeader = ShbIpcGetShbMemHeader(pShbMemInst); |
| |
| DEBUG_LVL_26_TRACE2 |
| ("ShbIpcStopSignalingNewData(%p) pfnSignHndlrNewData=%p\n", |
| pShbInstance_p, pShbMemInst->m_pfnSigHndlrNewData); |
| if (pShbMemInst->m_pfnSigHndlrNewData != NULL) { // signal handler was set before |
| int iErr; |
| //set termination flag in mem header |
| pShbMemInst->m_iThreadTermFlag = 1; |
| |
| // check if thread is still running at all by sending the null-signal to this thread |
| /* iErr = kill_proc(pShbMemInst->m_tThreadNewDataId, 0, 1); */ |
| iErr = send_sig(0, pShbMemInst->m_tThreadNewDataId, 1); |
| if (iErr == 0) { |
| // wake up thread, because it is still running |
| wake_up_interruptible(&pShbMemHeader-> |
| m_WaitQueueNewData); |
| |
| //wait for termination of thread |
| wait_for_completion(&pShbMemInst->m_CompletionNewData); |
| } |
| |
| pShbMemInst->m_pfnSigHndlrNewData = NULL; |
| pShbMemInst->m_tThreadNewDataId = INVALID_ID; |
| } |
| |
| return ShbError; |
| |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Signal new data (called from writing process) |
| //--------------------------------------------------------------------------- |
| |
| INLINE_FUNCTION tShbError ShbIpcSignalNewData(tShbInstance pShbInstance_p) |
| { |
| tShbMemHeader *pShbMemHeader; |
| |
| if (pShbInstance_p == NULL) { |
| return (kShbInvalidArg); |
| } |
| pShbMemHeader = |
| ShbIpcGetShbMemHeader(ShbIpcGetShbMemInst(pShbInstance_p)); |
| //set semaphore |
| pShbMemHeader->m_fNewData = TRUE; |
| DEBUG_LVL_29_TRACE0("ShbIpcSignalNewData set Sem -> New Data\n"); |
| |
| wake_up_interruptible(&pShbMemHeader->m_WaitQueueNewData); |
| return (kShbOk); |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Start signaling for job ready (called from waiting process) |
| //--------------------------------------------------------------------------- |
| |
| INLINE_FUNCTION tShbError ShbIpcStartSignalingJobReady(tShbInstance |
| pShbInstance_p, |
| unsigned long |
| ulTimeOut_p, |
| tSigHndlrJobReady |
| pfnSignalHandlerJobReady_p) |
| { |
| tShbMemInst *pShbMemInst; |
| tShbMemHeader *pShbMemHeader; |
| tShbError ShbError; |
| |
| if ((pShbInstance_p == NULL) || (pfnSignalHandlerJobReady_p == NULL)) { |
| return (kShbInvalidArg); |
| } |
| pShbMemInst = ShbIpcGetShbMemInst(pShbInstance_p); |
| pShbMemHeader = ShbIpcGetShbMemHeader(pShbMemInst); |
| |
| ShbError = kShbOk; |
| if ((pShbMemInst->m_tThreadJobReadyId != INVALID_ID) |
| || (pShbMemInst->m_pfnSigHndlrJobReady != NULL)) { |
| ShbError = kShbAlreadySignaling; |
| goto Exit; |
| } |
| pShbMemInst->m_ulTimeOutJobReady = ulTimeOut_p; |
| pShbMemInst->m_pfnSigHndlrJobReady = pfnSignalHandlerJobReady_p; |
| pShbMemHeader->m_fJobReady = FALSE; |
| //create thread for signalling new data |
| pShbMemInst->m_tThreadJobReadyId = |
| kernel_thread(ShbIpcThreadSignalJobReady, pShbInstance_p, |
| CLONE_KERNEL); |
| Exit: |
| return ShbError; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Signal job ready (called from executing process) |
| //--------------------------------------------------------------------------- |
| |
| INLINE_FUNCTION tShbError ShbIpcSignalJobReady(tShbInstance pShbInstance_p) |
| { |
| tShbMemHeader *pShbMemHeader; |
| |
| DEBUG_LVL_29_TRACE0("ShbIpcSignalJobReady\n"); |
| if (pShbInstance_p == NULL) { |
| return (kShbInvalidArg); |
| } |
| pShbMemHeader = |
| ShbIpcGetShbMemHeader(ShbIpcGetShbMemInst(pShbInstance_p)); |
| //set semaphore |
| pShbMemHeader->m_fJobReady = TRUE; |
| DEBUG_LVL_29_TRACE0("ShbIpcSignalJobReady set Sem -> Job Ready \n"); |
| |
| wake_up_interruptible(&pShbMemHeader->m_WaitQueueJobReady); |
| return (kShbOk); |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Get pointer to common used share memory area |
| //--------------------------------------------------------------------------- |
| |
| INLINE_FUNCTION void *ShbIpcGetShMemPtr(tShbInstance pShbInstance_p) |
| { |
| |
| tShbMemHeader *pShbMemHeader; |
| void *pShbShMemPtr; |
| |
| pShbMemHeader = |
| ShbIpcGetShbMemHeader(ShbIpcGetShbMemInst(pShbInstance_p)); |
| if (pShbMemHeader != NULL) { |
| pShbShMemPtr = (BYTE *) pShbMemHeader + sizeof(tShbMemHeader); |
| } else { |
| pShbShMemPtr = NULL; |
| } |
| |
| return (pShbShMemPtr); |
| |
| } |
| |
| #endif |
| |
| //=========================================================================// |
| // // |
| // P R I V A T E F U N C T I O N S // |
| // // |
| //=========================================================================// |
| |
| #if !defined(SHBIPC_INLINE_ENABLED) |
| |
| //--------------------------------------------------------------------------- |
| // Get pointer to process local information structure |
| //--------------------------------------------------------------------------- |
| |
| /*tShbMemInst* ShbIpcGetShbMemInst ( |
| tShbInstance pShbInstance_p) |
| { |
| |
| tShbMemInst* pShbMemInst; |
| |
| pShbMemInst = (tShbMemInst*)pShbInstance_p; |
| |
| return (pShbMemInst); |
| |
| } |
| */ |
| |
| //--------------------------------------------------------------------------- |
| // Get pointer to shared memory header |
| //--------------------------------------------------------------------------- |
| |
| /*tShbMemHeader* ShbIpcGetShbMemHeader ( |
| tShbMemInst* pShbMemInst_p) |
| { |
| |
| tShbMemHeader* pShbMemHeader; |
| |
| pShbMemHeader = pShbMemInst_p->m_pShbMemHeader; |
| |
| return (pShbMemHeader); |
| |
| } |
| */ |
| |
| //--------------------------------------------------------------------------- |
| // Allocate a memory block from process specific mempool |
| //--------------------------------------------------------------------------- |
| |
| static void *ShbIpcAllocPrivateMem(unsigned long ulMemSize_p) |
| { |
| tShbError ShbError; |
| void *pMem; |
| |
| DEBUG_LVL_29_TRACE0("ShbIpcAllocPrivateMem \n"); |
| //get private mem |
| pMem = kmalloc(ulMemSize_p, GFP_KERNEL); |
| if (pMem == NULL) { |
| //unable to create mem |
| ShbError = kShbOutOfMem; |
| goto Exit; |
| } |
| Exit: |
| return (pMem); |
| |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Thread for new data signaling |
| //--------------------------------------------------------------------------- |
| |
| int ShbIpcThreadSignalNewData(void *pvThreadParam_p) |
| { |
| tShbInstance pShbInstance; |
| tShbMemInst *pShbMemInst; |
| tShbMemHeader *pShbMemHeader; |
| int iRetVal = -1; |
| int fCallAgain; |
| |
| daemonize("ShbND%p", pvThreadParam_p); |
| allow_signal(SIGTERM); |
| pShbInstance = (tShbMemInst *) pvThreadParam_p; |
| pShbMemInst = ShbIpcGetShbMemInst(pShbInstance); |
| pShbMemHeader = ShbIpcGetShbMemHeader(pShbMemInst); |
| |
| DEBUG_LVL_26_TRACE1("ShbIpcThreadSignalNewData(%p)\n", pvThreadParam_p); |
| |
| set_user_nice(current, pShbMemInst->m_lThreadNewDataNice); |
| |
| // DEBUG_LVL_29_TRACE1("ShbIpcThreadSignalNewData wait for New Data Sem %p\n",pShbMemInst->m_pSemNewData); |
| do { |
| iRetVal = |
| wait_event_interruptible(pShbMemHeader->m_WaitQueueNewData, |
| (pShbMemInst->m_iThreadTermFlag != |
| 0) |
| || (pShbMemHeader->m_fNewData != |
| FALSE)); |
| |
| if (iRetVal != 0) { // signal pending |
| break; |
| } |
| |
| if (pShbMemHeader->m_fNewData != FALSE) { |
| pShbMemHeader->m_fNewData = FALSE; |
| do { |
| fCallAgain = |
| pShbMemInst-> |
| m_pfnSigHndlrNewData(pShbInstance); |
| // call scheduler, which will execute any task with higher priority |
| schedule(); |
| } while (fCallAgain != FALSE); |
| } |
| } while (pShbMemInst->m_iThreadTermFlag == 0); |
| DEBUG_LVL_29_TRACE0("ShbIpcThreadSignalNewData terminated \n"); |
| //set thread completed |
| complete_and_exit(&pShbMemInst->m_CompletionNewData, 0); |
| return 0; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Thread for new data Job Ready signaling |
| //--------------------------------------------------------------------------- |
| |
| int ShbIpcThreadSignalJobReady(void *pvThreadParam_p) |
| { |
| tShbInstance pShbInstance; |
| tShbMemInst *pShbMemInst; |
| tShbMemHeader *pShbMemHeader; |
| long lTimeOut; |
| int iRetVal = -1; |
| |
| daemonize("ShbJR%p", pvThreadParam_p); |
| allow_signal(SIGTERM); |
| pShbInstance = (tShbMemInst *) pvThreadParam_p; |
| pShbMemInst = ShbIpcGetShbMemInst(pShbInstance); |
| pShbMemHeader = ShbIpcGetShbMemHeader(pShbMemInst); |
| |
| DEBUG_LVL_29_TRACE0 |
| ("ShbIpcThreadSignalJobReady wait for job ready Sem\n"); |
| if (pShbMemInst->m_ulTimeOutJobReady != 0) { |
| lTimeOut = (long)pShbMemInst->m_ulTimeOutJobReady; |
| //wait for job ready semaphore |
| iRetVal = |
| wait_event_interruptible_timeout(pShbMemHeader-> |
| m_WaitQueueJobReady, |
| (pShbMemHeader-> |
| m_fJobReady != FALSE), |
| lTimeOut); |
| } else { |
| //wait for job ready semaphore |
| iRetVal = |
| wait_event_interruptible(pShbMemHeader->m_WaitQueueJobReady, |
| (pShbMemHeader->m_fJobReady != |
| FALSE)); |
| } |
| |
| if (pShbMemInst->m_pfnSigHndlrJobReady != NULL) { |
| //call Handler |
| pShbMemInst->m_pfnSigHndlrJobReady(pShbInstance, |
| !pShbMemHeader->m_fJobReady); |
| } |
| |
| pShbMemInst->m_pfnSigHndlrJobReady = NULL; |
| return 0; |
| } |
| |
| //Build the crc table |
| static void ShbIpcCrc32GenTable(unsigned long aulCrcTable[256]) |
| { |
| unsigned long ulCrc, ulPoly; |
| int iIndexI, iIndexJ; |
| |
| ulPoly = 0xEDB88320L; |
| for (iIndexI = 0; iIndexI < 256; iIndexI++) { |
| ulCrc = iIndexI; |
| for (iIndexJ = 8; iIndexJ > 0; iIndexJ--) { |
| if (ulCrc & 1) { |
| ulCrc = (ulCrc >> 1) ^ ulPoly; |
| } else { |
| ulCrc >>= 1; |
| } |
| } |
| aulCrcTable[iIndexI] = ulCrc; |
| } |
| } |
| |
| //Calculate the crc value |
| static unsigned long ShbIpcCrc32GetCrc(const char *pcString, |
| unsigned long aulCrcTable[256]) |
| { |
| unsigned long ulCrc; |
| int iIndex; |
| |
| ulCrc = 0xFFFFFFFF; |
| for (iIndex = 0; iIndex < strlen(pcString); iIndex++) { |
| ulCrc = |
| ((ulCrc >> 8) & 0x00FFFFFF) ^ |
| aulCrcTable[(ulCrc ^ pcString[iIndex]) & 0xFF]; |
| } |
| return (ulCrc ^ 0xFFFFFFFF); |
| |
| } |
| |
| static void ShbIpcAppendListElement(struct sShbMemTable *psNewMemTableElement) |
| { |
| struct sShbMemTable *psMemTableElement = psMemTableElementFirst_g; |
| psNewMemTableElement->m_psNextMemTableElement = NULL; |
| |
| if (psMemTableElementFirst_g != NULL) { /* sind Elemente vorhanden */ |
| while (psMemTableElement->m_psNextMemTableElement != NULL) { /* suche das letzte Element */ |
| psMemTableElement = |
| psMemTableElement->m_psNextMemTableElement; |
| } |
| psMemTableElement->m_psNextMemTableElement = psNewMemTableElement; /* Haenge das Element hinten an */ |
| } else { /* wenn die liste leer ist, bin ich das erste Element */ |
| psMemTableElementFirst_g = psNewMemTableElement; |
| } |
| } |
| |
| static int ShbIpcFindListElement(int iBufferId, |
| struct sShbMemTable **ppsReturnMemTableElement) |
| { |
| struct sShbMemTable *psMemTableElement = psMemTableElementFirst_g; |
| while (psMemTableElement != NULL) { |
| if (psMemTableElement->m_iBufferId == iBufferId) { |
| //printk("ShbIpcFindListElement Buffer at:%p Id:%d\n",psMemTableElement->m_pBuffer,psMemTableElement->m_iBufferId); |
| *ppsReturnMemTableElement = psMemTableElement; |
| //printk("ShbIpcFindListElement Buffer at:%p Id:%d\n",(*ppsReturnMemTableElement)->m_pBuffer,(*ppsReturnMemTableElement)->m_iBufferId); |
| return 0; |
| } |
| psMemTableElement = psMemTableElement->m_psNextMemTableElement; |
| } |
| return -1; |
| } |
| |
| static void ShbIpcDeleteListElement(int iBufferId) |
| { |
| struct sShbMemTable *psMemTableElement = psMemTableElementFirst_g; |
| struct sShbMemTable *psMemTableElementOld = psMemTableElementFirst_g; |
| if (psMemTableElement != NULL) { |
| while ((psMemTableElement != NULL) |
| && (psMemTableElement->m_iBufferId != iBufferId)) { |
| psMemTableElementOld = psMemTableElement; |
| psMemTableElement = |
| psMemTableElement->m_psNextMemTableElement; |
| } |
| if (psMemTableElement != NULL) { |
| if (psMemTableElement != psMemTableElementFirst_g) { |
| psMemTableElementOld->m_psNextMemTableElement = |
| psMemTableElement->m_psNextMemTableElement; |
| kfree(psMemTableElement); |
| } else { |
| kfree(psMemTableElement); |
| psMemTableElementFirst_g = NULL; |
| } |
| |
| } |
| } |
| |
| } |
| |
| #endif |