allswellthatendswell
2016-01-04 12:55:58 UTC
{ edited by mod to shorten text lines to ~70 characters. the source
and command lines have not been edited. -mod }
The following C++ program , DataServer.cpp, throws a segmentation
fault at the exit of the extern "C" function, void func(void) shown
in the bottom of this question. I compiled this program on Ubuntu
Linux 14.04 LTS with the g++ entry point feature.
g++ -shared -g -fPIC -DLINUX -Wl,-soname,libdataserver.so -efunc -I
/home/venkat/Downloads/waitForMultipleObjects -I
/home/venkat/developmentMono/SmartCamXi_Hybrid/Include DataServer.cpp
DataServerLib.cpp DataTransferClient.cpp CWinEventHandle.cpp WinEvent.cpp
-lpthread -lrt
When I run gdb ./a.out core, I get the following output:
:~/Downloads/DataServerLib$ gdb ./a.out
Reading symbols from ./a.out...done.
[New LWP 8538]
Core was generated by `./a.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000000000000001 in ?? ()
(gdb) bt
#0 0x0000000000000001 in ?? ()
#1 0x00007ffdab79f29e in ?? ()
#2 0x0000000000000000 in ?? ()
(gdb) where
#0 0x0000000000000001 in ?? ()
#1 0x00007ffdab79f29e in ?? ()
#2 0x0000000000000000 in ?? ()
(gdb) list
1 #include <stdio.h>
2 #ifndef LINUX
3 #include <aclapi.h>
4 #else
5 #include <errno.h>
6 #endif
7 #include "DataServer.h"
8 #include "CameraControlDefs.h"
9 #include <iostream>
10 #include <unistd.h>
I would like to find out the cause of the segmentation fault and how to
possibly fix it. I have already examined the delete srv source code
line at the end of the extern "C" function , void func(void) and the
CDataTransferServer destructor appears to function properly.
Any help is greatly appreciated.
#include <stdio.h>
#ifndef LINUX
#include <aclapi.h>
#else
#include <errno.h>
#endif
#include "DataServer.h"
#include "CameraControlDefs.h"
#include <iostream>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <wchar.h>
#include "winEmul.h"
#ifdef LINUX
#include <semaphore.h>
#include <unistd.h>
#endif
//#include "SmartLog.h"
#ifdef LINUX
typedef void* PSECURITY_DESCRIPTOR;
typedef unsigned int DWORD;
#endif
#ifdef LINUX
inline int memcpy_s(void* dest, size_t numberOfElements, const void *src,
size_t count)
{
memcpy(dest, src, count);
return errno;
}
#endif
#ifdef __LP64__
const char service_interp[] __attribute__((section(".interp"))) =
"/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2";
#else
const char service_interp[] __attribute__((section(".interp"))) =
"/lib/ld-linux.so.2";
#endif
////////////////////////////////////////////////////////////////////////////
//////////////////////
// CDataTransferUser
//==========================================================================
======================
CDataTransferUser::CDataTransferUser()
{
m_bInitialized = false;
m_hSharedMemory = NULL;
m_pControl = NULL;
m_hMutexControl = NULL;
}
//==========================================================================
======================
CDataTransferUser::~CDataTransferUser()
{
if (m_pControl)
{
#ifndef LINUX
::UnmapViewOfFile(m_pControl);
#else
munmap(m_pControl,0);
#endif
}
if (m_hSharedMemory)
::CloseHandle(m_hSharedMemory);
if (m_hMutexControl)
::CloseHandle(m_hMutexControl);
}
// The following function initializes the supplied security descriptor
// with a DACL that grants the Authenticated Users group GENERIC_READ,
// GENERIC_WRITE, and GENERIC_EXECUTE access.
//
// The function returns NULL if any of the access control APIs fail.
// Otherwise, it returns a PVOID pointer that should be freed by calling
// FreeRestrictedSD() after the security descriptor has been used to
// create the object.
#ifdef LINUX
void* CDataTransferUser::BuildRestrictedSD(void* pSD)
#else
void* CDataTransferUser::BuildRestrictedSD(PSECURITY_DESCRIPTOR pSD)
#endif
{
#ifdef LINUX
return NULL;
#else
DWORD dwAclLength;
PSID pAuthenticatedUsersSID = NULL;
PACL pDACL = NULL;
BOOL bResult = FALSE;
PACCESS_ALLOWED_ACE pACE = NULL;
SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY;
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
__try
{
// initialize the security descriptor
if (!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION))
{
printf("InitializeSecurityDescriptor() failed with error %d\n",
GetLastError());
__leave;
}
// obtain a sid for the Authenticated Users Group
if (!AllocateAndInitializeSid(&siaNT, 1,
SECURITY_AUTHENTICATED_USER_RID, 0, 0, 0, 0, 0, 0, 0,
&pAuthenticatedUsersSID))
{
printf("AllocateAndInitializeSid() failed with error %d\n",
GetLastError());
__leave;
}
// NOTE:
//
// The Authenticated Users group includes all user accounts that
// have been successfully authenticated by the system. If access
// must be restricted to a specific user or group other than
// Authenticated Users, the SID can be constructed using the
// LookupAccountSid() API based on a user or group name.
// calculate the DACL length
dwAclLength = sizeof(ACL)
// add space for Authenticated Users group ACE
+ sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)
+ GetLengthSid(pAuthenticatedUsersSID);
// allocate memory for the DACL
pDACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
dwAclLength);
if (!pDACL)
{
printf("HeapAlloc() failed with error %d\n", GetLastError());
__leave;
}
// initialize the DACL
if (!InitializeAcl(pDACL, dwAclLength, ACL_REVISION))
{
printf("InitializeAcl() failed with error %d\n",
GetLastError());
__leave;
}
// add the Authenticated Users group ACE to the DACL with
// GENERIC_READ, GENERIC_WRITE, and GENERIC_EXECUTE access
if (!AddAccessAllowedAce(pDACL, ACL_REVISION,
GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
pAuthenticatedUsersSID))
{
printf("AddAccessAllowedAce() failed with error %d\n",
GetLastError());
__leave;
}
// set the DACL in the security descriptor
if (!SetSecurityDescriptorDacl(pSD, TRUE, pDACL, FALSE))
{
printf("SetSecurityDescriptorDacl() failed with error %d\n",
GetLastError());
__leave;
}
bResult = TRUE;
} __finally
{
if (pAuthenticatedUsersSID)
FreeSid(pAuthenticatedUsersSID);
}
if (bResult == FALSE)
{
if (pDACL)
HeapFree(GetProcessHeap(), 0, pDACL);
pDACL = NULL;
}
return (void*) pDACL;
#endif // ends Windows code
}
// The following function frees memory allocated in the
// BuildRestrictedSD() function
void CDataTransferUser::FreeRestrictedSD(void* ptr)
{
#ifndef LINUX
if (ptr)
HeapFree(GetProcessHeap(), 0, ptr);
#endif
return;
}
////////////////////////////////////////////////////////////////////////////
//////////////////////
// CDataTransferServer
//==========================================================================
======================
CDataTransferServer::CDataTransferServer()
{
m_nCameraID = 0;
m_nFileMapSize = 0;
m_nMaxFrames = 0;
m_nMaxConfigSize = 0;
m_nConfigBlocks = 0;
m_bKeyBlock = false;
m_nMaxDataSize = 0;
m_nControlSize = 0;
m_nUserReferenceCount = 0;
m_szObjNameSuffix[0] = '\0';
m_nLastSendTime = 0;
m_nDistanceFromKeyData = 0;
m_nLastErrorLoggedIgnoreFrames = 0;
m_nPFramesIgnored = 0;
#ifndef LINUX
::InitializeCriticalSectionAndSpinCount(&m_lockEvents, 0x80000400);
#else
pthread_mutexattr_t mutexattr;
pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_mutex_init(&m_lockEvents,&mutexattr);
#endif
}
//==========================================================================
======================
CDataTransferServer::~CDataTransferServer()
{
// Close all of the events
#ifndef LINUX
::EnterCriticalSection(&m_lockEvents);
#else
pthread_mutex_lock(&m_lockEvents);
#endif
while (m_mapUserEvents.size() > 0)
{
::CloseHandle(m_mapUserEvents.begin()->second.hEvent);
printf("before m_mapUserEvents erase size() =
%d\n",m_mapUserEvents.size());
m_mapUserEvents.erase(m_mapUserEvents.begin());
printf("after m_mapUserEvents erase size() =
%d\n",m_mapUserEvents.size());
}
#ifndef LINUX
::LeaveCriticalSection(&m_lockEvents);
#else
pthread_mutex_unlock(&m_lockEvents);
printf("pthread_mutex_unlock\n");
#endif
#ifndef LINUX
::DeleteCriticalSection(&m_lockEvents);
#else
pthread_mutex_destroy(&m_lockEvents);
printf("pthread_mutex_destroy\n");
#endif
}
//==========================================================================
======================
bool CDataTransferServer::AddUser(unsigned int nUserID, std::wstring&
strMemoryName,
std::wstring&
strMutexName, std::wstring& strEventName)
{
printf("AddUser\n");
#ifndef LINUX
::EnterCriticalSection(&m_lockEvents);
#else
pthread_mutex_lock(&m_lockEvents);
#endif
if (m_mapUserEvents.find(nUserID) == m_mapUserEvents.end())
{
++m_nUserReferenceCount;
UserEventInfo ei;
ei.strEventName = L"Global\\SmartCamEvent";
#ifdef LINUX
wchar_t arg[512];
mbstowcs(arg,m_szObjNameSuffix,512);
ei.strEventName += arg;
#else
ei.strEventName += m_szObjNameSuffix;
#endif
printf("AddUser2\n");
#ifdef LINUX
wchar_t szUserID[16];
swprintf(szUserID, sizeof(szUserID) / sizeof(*szUserID) ,
L"_%x", nUserID);
ei.strEventName += szUserID;
#else
TCHAR szUserID[16];
wsprintf(szUserID, L"_%x", nUserID);
ei.strEventName += szUserID;
#endif
#ifndef LINUX
SECURITY_ATTRIBUTES sa;
LPSECURITY_ATTRIBUTES lpEventAttributes = &sa;
SECURITY_DESCRIPTOR sd;
sa.nLength = sizeof sa;
sa.bInheritHandle = FALSE;
sa.lpSecurityDescriptor = &sd;
void* pDACL = BuildRestrictedSD(&sd);
if (pDACL == NULL)
lpEventAttributes = NULL;
ei.hEvent = CreateEvent(lpEventAttributes, FALSE, FALSE,
ei.strEventName.c_str());
#else
ei.hEvent = CreateEvent(NULL, false, false,
ei.strEventName.c_str());
printf("AddUser3\n");
#endif
ei.nLastEventConsumedTime = 0;
#ifndef LINUX
if (pDACL)
FreeRestrictedSD(pDACL);
#endif
m_mapUserEvents[nUserID] = ei;
}
strEventName = m_mapUserEvents[nUserID].strEventName;
strMemoryName = m_strMemoryName;
strMutexName = m_strMutexName;
printf("AddUser4\n");
#ifndef LINUX
::LeaveCriticalSection(&m_lockEvents);
#else
pthread_mutex_unlock(&m_lockEvents);
#endif
return true;
}
//==========================================================================
======================
bool CDataTransferServer::RemoveUser(unsigned int nUserID)
{
#ifndef LINUX
::EnterCriticalSection(&m_lockEvents);
#else
pthread_mutex_lock(&m_lockEvents);
#endif
CUserEventMap::iterator itEvent = m_mapUserEvents.find(nUserID);
if (itEvent != m_mapUserEvents.end())
{
if (m_nUserReferenceCount > 0)
--m_nUserReferenceCount;
::CloseHandle(itEvent->second.hEvent);
m_mapUserEvents.erase(itEvent);
}
#ifndef LINUX
::LeaveCriticalSection(&m_lockEvents);
#else
pthread_mutex_unlock(&m_lockEvents);
#endif
return true;
}
//==========================================================================
======================
bool CDataTransferServer::Initialize(int nCameraID, CC_SAMPLETYPE
nDataType,
unsigned
int nImageWidth, unsigned int nImageHeight,
unsigned
int nMaxFrames)
{
bool bOkay = true;
char buffer[64] = {0};
// This is going to be a problem if we try to re-initialize with a
different image size...
if (m_bInitialized)
return true;
m_nCameraID = nCameraID;
m_nMaxFrames = nMaxFrames;
if (m_nMaxFrames < 2)
m_nMaxFrames = 2;
// Calculate how much space we need for the data and headers
m_nMaxDataSize = 0;
m_nMaxConfigSize = 0;
m_nConfigBlocks = 0;
if (((nDataType & CC_SAMPLETYPE_MPEG4) == CC_SAMPLETYPE_MPEG4) ||
((nDataType & CC_SAMPLETYPE_MPEG4AVC) == CC_SAMPLETYPE_MPEG4AVC))
{
m_nMaxDataSize = (nImageWidth * nImageHeight) + 1024; // for
VideoFrame size and motion data
m_nMaxConfigSize = 1024;
m_nConfigBlocks = 1;
m_bKeyBlock = true;
}
else if (nDataType == CC_SAMPLETYPE_UNCOMPRESSEDVIDEO_YUY2)
{
m_nMaxDataSize = (nImageWidth * nImageHeight * 2) + 1024; //
for VideoFrame size and motion data
m_nMaxConfigSize = 0;
}
else if (nDataType == CC_SAMPLETYPE_MJPEG)
{
m_nMaxDataSize = (nImageWidth * nImageHeight) + 1024; // for
VideoFrame size and motion data
m_nMaxConfigSize = 0;
}
m_nMaxFrames += m_bKeyBlock ? 1 : 0;
m_nMaxDataSize += 4 + sizeof(uTypeSpecificSize);
m_nControlSize = sizeof(CDataTransferControl);
// Control Block
m_nControlSize += (m_nMaxFrames - 1) *
sizeof(CDataTransferBlockHeader); // Data Block Headers
if (m_nMaxConfigSize > 0)
m_nControlSize += sizeof(CDataTransferBlockHeader);
// Make sure the control size is DWORD-aligned
while ((m_nControlSize & 0x03) != 0)
++m_nControlSize;
m_nFileMapSize = m_nControlSize + m_nMaxFrames * m_nMaxDataSize;
// Data Blocks
if (m_nMaxConfigSize > 0)
m_nFileMapSize += m_nMaxConfigSize;
// Config Header & Config Data
// Suffix for global objects (file map and sync objects) based on
camera ID and data type
#ifdef LINUX
sprintf(m_szObjNameSuffix, "_%x_%x", nCameraID, nDataType);
#else
::swprintf_s(m_szObjNameSuffix, 31, L"_%x_%x", nCameraID,
nDataType);
#endif
#ifndef LINUX
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
sa.nLength = sizeof sa;
sa.bInheritHandle = FALSE;
sa.lpSecurityDescriptor = &sd;
void* pDACL = BuildRestrictedSD(&sd);
if (pDACL == NULL)
bOkay = false;
#endif
if (bOkay)
{
if (m_hMutexControl == NULL)
{
m_strMutexName = L"Global\\SmartCamMutex";
#ifdef LINUX
m_hMutexControl = sem_open(buffer, O_CREAT, 0600,
0);
#else
m_hMutexControl = ::CreateMutex(&sa, TRUE,
m_strMutexName.c_str());
#endif
if (m_hMutexControl == NULL)
bOkay = false;
}
}
#ifdef LINUX
if (bOkay)
{
char buffer[256];
wcstombs(buffer,m_strMemoryName.c_str(),256);
FILE* stream = fopen(buffer, "rw");
int fd = fileno(stream);
m_pControl = (CDataTransferControl*)mmap(NULL,
m_nFileMapSize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if (m_pControl)
{
memset(m_pControl, 0, m_nControlSize);
m_pControl->nConfigurationBlock = 0xffffffff;
m_pControl->nNewestKeyDataBlock = 0xffffffff;
m_pControl->nNewestDataBlock = 0xffffffff;
m_pControl->nBlockHeaders = m_nMaxFrames +
m_nConfigBlocks;
m_pControl->nTimeOfLastClientAccess = ::GetTickCount();
}
else
bOkay = false;
}
#else
if (bOkay)
{
if (m_hSharedMemory == NULL || m_hSharedMemory ==
INVALID_HANDLE_VALUE)
{
m_strMemoryName = L"Global\\SmartCamMem";
m_strMemoryName += m_szObjNameSuffix;
#ifdef LINUX
m_hSharedMemory =
#else
m_hSharedMemory =
::CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE,
#endif
0,, m_strMemoryName.c_str());
if (m_hSharedMemory == NULL || m_hSharedMemory ==
INVALID_HANDLE_VALUE)
bOkay = false;
}
}
if (bOkay)
{
if (m_pControl == NULL)
{
m_pControl =
(CDataTransferControl*)::MapViewOfFile(m_hSharedMemory,
FILE_MAP_ALL_ACCESS, 0, 0, m_nFileMapSize);
if (m_pControl)
{
::ZeroMemory(m_pControl, m_nControlSize);
m_pControl->nConfigurationBlock = 0xffffffff;
m_pControl->nNewestKeyDataBlock = 0xffffffff;
m_pControl->nNewestDataBlock = 0xffffffff;
m_pControl->nBlockHeaders = m_nMaxFrames +
m_nConfigBlocks;
m_pControl->nTimeOfLastClientAccess =
::GetTickCount();
}
else
bOkay = false;
}
}
#endif
#ifndef LINUX
if (pDACL)
FreeRestrictedSD(pDACL);
#endif
if (m_hMutexControl)
#ifndef LINUX
::ReleaseMutex(m_hMutexControl);
#endif
m_bInitialized = bOkay;
return bOkay;
}
//===========================================================:==============
=======================
bool CDataTransferServer::SendData(CVideoFrame *frame)
{
bool bFrameSent = false;
if (!m_bInitialized) return false;
if(frame == NULL) return false;
static DWORD dwWaitTime = 0;
static DWORD dwFramesSent = 0;
static DWORD dwFramesSkipped = 0;
bool bShowStats = false;
if (frame->GetSize() > m_nMaxDataSize)
{
#ifndef LINUX
::OutputDebugString(L"CDataTransferServer::SendData: Data
exceeds available size; data not posted to memory\n");
#else
cerr << "CDataTransferServer::SendData: Data exceeds available
size; data not posted to memory" << endl;
#endif
return false;
}
if (CheckPFrameCount(frame) == false)
return false;
// Wait for up to 25ms to lock the memory. That's a little shorter
than 1/30th of a
// second, which is our fastest video frame rate.
DWORD dwTimeStart = ::GetTickCount();
DWORD dwWait = ::WaitForSingleObject(m_hMutexControl, 25);
#ifndef LINUX
if (dwWait == WAIT_OBJECT_0 || dwWait == WAIT_ABANDONED)
#else
if (dwWait == WAIT_OBJECT_0)
#endif
{
DWORD dwTimeNow = ::GetTickCount();
dwWaitTime += dwTimeNow - dwTimeStart;
++dwFramesSent;
bShowStats = (dwTimeNow - dwTimeStart != 0);
unsigned long nBlock, nOffset;
bool bOkayToSendFrame = true;
unsigned long nNormalStartBlock = m_nConfigBlocks +
(m_bKeyBlock ? 1 : 0);
bool bCurrentKeyBlock = false;
// Wrap this section in try/except to handle exceptions thrown
by memory mapped file access
#ifndef LINUX
__try
#else
try
#endif
{
if (frame->GetType() == CC_SAMPLETYPE_MPEG4_CONFIG ||
frame->GetType() == CC_SAMPLETYPE_MPEG4AVC_CONFIG)
{
// Configuration data is always in block 0
nBlock = 0;
nOffset = 0;
m_pControl->nConfigurationBlock = nBlock;
}
else if ((frame->GetType() == CC_SAMPLETYPE_MPEG4_IFRAME
|| frame->GetType() == CC_SAMPLETYPE_MPEG4AVC_IFRAME) && m_bKeyBlock)
{
// Key data is always in the block after the
configuration block
// This block will be overwritten even if somebody
is using it. We should get
// key data infrequently enough so that this won't
be a problem.
bCurrentKeyBlock = true;
nBlock = m_nConfigBlocks;
nOffset = m_nMaxConfigSize + (nBlock -
m_nConfigBlocks) * m_nMaxDataSize;
m_pControl->nNewestKeyDataBlock = nBlock;
m_pControl->nNewestDataBlock = nBlock;
m_pControl->nTimeOfNewestKeyDataBlock = dwTimeNow;
m_pControl->nTimeOfNewestDataBlock = dwTimeNow;
}
else
{
// Normal data -- get the next block that is not
being read
bool bContinue = true;
nBlock = m_pControl->nNewestDataBlock;
unsigned long nStartBlock = nBlock;
do
{
if (m_pControl->nNewestDataBlock ==
0xffffffff) // First block?
{
nBlock = nNormalStartBlock;
bContinue = false;
}
else
{
++nBlock;
if (m_bKeyBlock && nBlock <
nNormalStartBlock || nBlock >= m_nMaxFrames + m_nConfigBlocks)
nBlock = nNormalStartBlock;
}
if
(m_pControl->aBlockHeaders[nBlock].nReaderReferenceCount == 0)
bContinue = false;
else
{
// This block is being read. Make sure
that the reader didn't timeout
static const DWORD nReaderTimeout =
30000;
DWORD dwElapsed;
if (dwTimeNow >=
m_pControl->aBlockHeaders[nBlock].nTimeOfLastRead)
dwElapsed = dwTimeNow -
m_pControl->aBlockHeaders[nBlock].nTimeOfLastRead;
else
{
// The time wrapped around back
to 0.
dwElapsed = 0xffffffff -
m_pControl->aBlockHeaders[nBlock].nTimeOfLastRead + dwTimeNow;
}
if (dwElapsed > nReaderTimeout)
{
// Read timed out, so we'll use
this block
m_pControl->aBlockHeaders[nBlock].nReaderReferenceCount = 0;
#ifndef LINUX
::OutputDebugString(L"CDataTransferServer: Releasing a block that was locked
for too long.\n");
#else
cerr << "CDataTransferServer:
Releasing a block that was locked for too long." << endl;
#endif
bContinue = false;
}
}
} while (bContinue && nBlock != nStartBlock);
// Did we find a good destination?
nOffset = m_nMaxConfigSize + (nBlock -
m_nConfigBlocks) * m_nMaxDataSize;
if
(m_pControl->aBlockHeaders[nBlock].nReaderReferenceCount == 0)
{
m_pControl->nNewestDataBlock = nBlock;
m_pControl->nTimeOfNewestDataBlock =
dwTimeNow;
}
else
bOkayToSendFrame = false;
}
// actual frame sent here
if (bOkayToSendFrame)
{
// Set the frame type into DataTransferControl
m_pControl->nSampleType = frame->GetType();
m_pControl->nDistanceFromKeyData =
frame->m_nDistanceFromKeyData;
// Set the header info for this block
//DWORD dwTimeNow = ::GetTickCount();
if (m_bKeyBlock)
{
if ((bCurrentKeyBlock) || (nBlock ==
m_pControl->nConfigurationBlock))
m_nDistanceFromKeyData = 0;
else
++m_nDistanceFromKeyData;
}
else
{ // MJPEG
m_nDistanceFromKeyData = 0;
}
nOffset += m_nControlSize;
m_pControl->aBlockHeaders[nBlock].nReaderReferenceCount = 0;
m_pControl->aBlockHeaders[nBlock].nDistanceFromKeyData =
m_nDistanceFromKeyData;
//m_pControl->aBlockHeaders[nBlock].nDistanceFromKeyData =
frame->m_nDistanceFromKeyData;
m_pControl->aBlockHeaders[nBlock].nDataOffset =
nOffset;
m_pControl->aBlockHeaders[nBlock].nDataType =
(unsigned long)frame->GetType();
m_pControl->aBlockHeaders[nBlock].nDataSize =
sizeof(DWORD) + frame->GetSize();
m_pControl->aBlockHeaders[nBlock].nTimeOfWrite =
dwTimeNow;
m_pControl->aBlockHeaders[nBlock].nTimeOfLastRead =
dwTimeNow;
// Write an offset to the real data -- 4 bytes
unsigned long nStartOfDataSize = 4;
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &nStartOfDataSize, nStartOfDataSize);
nOffset += 4;
// write frame header
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_type, sizeof(int)); // we have it header - send it
again anyway
nOffset += sizeof(int);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_width, sizeof(int));
nOffset += sizeof(int);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_height, sizeof(int));
nOffset += sizeof(int);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_dataLength, sizeof(long));
nOffset += sizeof(long);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_motionLength, sizeof(long));
nOffset += sizeof(long);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_motionWidth, sizeof(long));
nOffset += sizeof(long);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_motionHeight, sizeof(long));
nOffset += sizeof(long);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_record, sizeof(int));
nOffset += sizeof(int);
// write trigger
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_trigger, sizeof(int));
nOffset += sizeof(int);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_time, sizeof(__int64));
nOffset += sizeof(__int64);
// write motion block
if(frame->m_motionLength > 0)
{
::memcpy_s(((unsigned char*)m_pControl) +
nOffset, m_nMaxDataSize, frame->m_motion, frame->m_motionLength);
nOffset += frame->m_motionLength;
}
// write data
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, frame->m_data, frame->m_dataLength);
nOffset += frame->m_dataLength;
// we done
bFrameSent = true;
m_nLastSendTime = dwTimeNow;
}
}
#ifndef LINUX
__except (::GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ?
EXCEPTION_EXECUTE_HANDLER :
EXCEPTION_CONTINUE_SEARCH)
#else
catch(std::exception& e)
#endif
{
// Access to memory mapped file caused an exception
}
// Updated data is ready for clients
if (bFrameSent)
SetNewDataEvents();
#ifndef LINUX
::ReleaseMutex(m_hMutexControl);
#else
sem_close(m_hMutexControl);
#endif
}
else
{
++dwFramesSkipped;
bShowStats = true;
}
if (bShowStats)
{
wchar_t szMsg[128];
#ifdef LINUX
::swprintf(szMsg, 128, L"DataServer: %d frames sent (wait=%0.2f
ms), %d frames skipped\n", dwFramesSent, dwWaitTime / (double)dwFramesSent,
dwFramesSkipped);
#else
::swprintf_s(szMsg, L"DataServer: %d frames sent (wait=%0.2f
ms), %d frames skipped\n", dwFramesSent, dwWaitTime / (double)dwFramesSent,
dwFramesSkipped);
#endif
#ifndef LINUX
::OutputDebugString(szMsg);
#else
cerr << szMsg << endl;
#endif
}
return bFrameSent;
}
bool CDataTransferServer::CheckPFrameCount(CVideoFrame *frame)
{
if ((frame->GetType() == CC_SAMPLETYPE_MPEG4_PFRAME) ||
(frame->GetType() == CC_SAMPLETYPE_MPEG4AVC_PFRAME))
{
if (frame->m_nDistanceFromKeyData > (m_nMaxFrames - 2))
// 2 = IFrame + Config Block
{ // We received more P frames than we are expecting,
#ifndef LINUX
::OutputDebugString(L"CDataTransferServer::SendData:
received more P frames than expected, ignoring the frames\n");
#else
cerr << "CDataTransferServer::SendData: received more P
frames than expected, ignoring the frames" << endl;
#endif
m_nPFramesIgnored ++;
//DWORD dwNow = ::GetTickCount();
//if(dwNow - m_nLastErrorLoggedIgnoreFrames > 1000*60*60)
// don't log too often - once in hour
//{
// m_nLastErrorLoggedIgnoreFrames = dwNow;
// try
// {
// CLogFile* pLogFile = new
CLogFile(L"SmartCamXi_NVR_Recorder.log", TRUE);
// if(pLogFile != NULL)
// {
// TCHAR tmp[MAX_PATH];
// _stprintf(tmp, L"Ignoring P Frames -
I Frame Interval is not set correctly - CameraControlLib: Camera ID: %d,
Expected I Frame Interval: %d \n", m_nCameraID, m_nMaxFrames - 2);
// pLogFile->Write(tmp);
// delete pLogFile;
// }
// }
// catch (...)
// {
// }
// m_nPFramesIgnored = 0;
//}
return false;
}
}
return true;
}
//==========================================================================
======================
void CDataTransferServer::SetNewDataEvents()
{
DWORD dwNow = ::GetTickCount();
unsigned int nRemoveThisID = 0xffffffff;
#ifndef LINUX
::EnterCriticalSection(&m_lockEvents);
#else
pthread_mutex_lock(&m_lockEvents);
#endif
CUserEventMap::iterator itEvent = m_mapUserEvents.begin();
while (itEvent != m_mapUserEvents.end())
{
// Check to see if the previous event has been consumed
if (::WaitForSingleObject(itEvent->second.hEvent, 0) ==
WAIT_OBJECT_0)
{
// It hasn't -- make sure it hasn't been inactive for too
long
DWORD dwElapsed;
if (itEvent->second.nLastEventConsumedTime == 0)
{
// This event hasn't been set yet, so don't try to
check the time
dwElapsed = 0;
}
else if (dwNow >= itEvent->second.nLastEventConsumedTime)
dwElapsed = dwNow -
itEvent->second.nLastEventConsumedTime;
else
{
// The time wrapped around back to 0.
dwElapsed = 0xffffffff -
itEvent->second.nLastEventConsumedTime + dwNow;
}
if (dwElapsed > 300000) // 5 minute timeout
nRemoveThisID = itEvent->first;
}
else
itEvent->second.nLastEventConsumedTime = dwNow;
::SetEvent(itEvent->second.hEvent);
++itEvent;
}
// Remove one user if the event has timed out. This will only remove
one user each
// time in this function, but this is called frequently.
if (nRemoveThisID != 0xffffffff)
RemoveUser(nRemoveThisID);
#ifndef LINUX
::LeaveCriticalSection(&m_lockEvents);
#else
pthread_mutex_lock(&m_lockEvents);
#endif
}
extern "C"
{
int func() /* THIS IS WHERE THE PROBLEM IS */
{
wchar_t memoryName[256];
wchar_t mutexName[256];
wchar_t eventName[256];
mbstowcs(memoryName, "MemoryName", 256);
mbstowcs(mutexName, "MutexName", 256);
mbstowcs(eventName, "EventName", 256);
std::wstring memoryString(memoryName);
std::wstring mutexString(mutexName);
std::wstring eventString(eventName);
CDataTransferServer *srv = new CDataTransferServer();
srv->Initialize(1, CC_SAMPLETYPE_MPEG4,128,256,64);
printf("Inside entry point tester 1\n");
srv->AddUser(5, memoryString, mutexString, eventString);
printf("Inside entry point tester 2\n");
delete srv;
printf("Exiting entry point tester \n");
/* THIS IS WHERE THE PROBLEM IS */
}
}
and command lines have not been edited. -mod }
The following C++ program , DataServer.cpp, throws a segmentation
fault at the exit of the extern "C" function, void func(void) shown
in the bottom of this question. I compiled this program on Ubuntu
Linux 14.04 LTS with the g++ entry point feature.
g++ -shared -g -fPIC -DLINUX -Wl,-soname,libdataserver.so -efunc -I
/home/venkat/Downloads/waitForMultipleObjects -I
/home/venkat/developmentMono/SmartCamXi_Hybrid/Include DataServer.cpp
DataServerLib.cpp DataTransferClient.cpp CWinEventHandle.cpp WinEvent.cpp
-lpthread -lrt
When I run gdb ./a.out core, I get the following output:
:~/Downloads/DataServerLib$ gdb ./a.out
Reading symbols from ./a.out...done.
[New LWP 8538]
Core was generated by `./a.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000000000000001 in ?? ()
(gdb) bt
#0 0x0000000000000001 in ?? ()
#1 0x00007ffdab79f29e in ?? ()
#2 0x0000000000000000 in ?? ()
(gdb) where
#0 0x0000000000000001 in ?? ()
#1 0x00007ffdab79f29e in ?? ()
#2 0x0000000000000000 in ?? ()
(gdb) list
1 #include <stdio.h>
2 #ifndef LINUX
3 #include <aclapi.h>
4 #else
5 #include <errno.h>
6 #endif
7 #include "DataServer.h"
8 #include "CameraControlDefs.h"
9 #include <iostream>
10 #include <unistd.h>
I would like to find out the cause of the segmentation fault and how to
possibly fix it. I have already examined the delete srv source code
line at the end of the extern "C" function , void func(void) and the
CDataTransferServer destructor appears to function properly.
Any help is greatly appreciated.
#include <stdio.h>
#ifndef LINUX
#include <aclapi.h>
#else
#include <errno.h>
#endif
#include "DataServer.h"
#include "CameraControlDefs.h"
#include <iostream>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <wchar.h>
#include "winEmul.h"
#ifdef LINUX
#include <semaphore.h>
#include <unistd.h>
#endif
//#include "SmartLog.h"
#ifdef LINUX
typedef void* PSECURITY_DESCRIPTOR;
typedef unsigned int DWORD;
#endif
#ifdef LINUX
inline int memcpy_s(void* dest, size_t numberOfElements, const void *src,
size_t count)
{
memcpy(dest, src, count);
return errno;
}
#endif
#ifdef __LP64__
const char service_interp[] __attribute__((section(".interp"))) =
"/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2";
#else
const char service_interp[] __attribute__((section(".interp"))) =
"/lib/ld-linux.so.2";
#endif
////////////////////////////////////////////////////////////////////////////
//////////////////////
// CDataTransferUser
//==========================================================================
======================
CDataTransferUser::CDataTransferUser()
{
m_bInitialized = false;
m_hSharedMemory = NULL;
m_pControl = NULL;
m_hMutexControl = NULL;
}
//==========================================================================
======================
CDataTransferUser::~CDataTransferUser()
{
if (m_pControl)
{
#ifndef LINUX
::UnmapViewOfFile(m_pControl);
#else
munmap(m_pControl,0);
#endif
}
if (m_hSharedMemory)
::CloseHandle(m_hSharedMemory);
if (m_hMutexControl)
::CloseHandle(m_hMutexControl);
}
// The following function initializes the supplied security descriptor
// with a DACL that grants the Authenticated Users group GENERIC_READ,
// GENERIC_WRITE, and GENERIC_EXECUTE access.
//
// The function returns NULL if any of the access control APIs fail.
// Otherwise, it returns a PVOID pointer that should be freed by calling
// FreeRestrictedSD() after the security descriptor has been used to
// create the object.
#ifdef LINUX
void* CDataTransferUser::BuildRestrictedSD(void* pSD)
#else
void* CDataTransferUser::BuildRestrictedSD(PSECURITY_DESCRIPTOR pSD)
#endif
{
#ifdef LINUX
return NULL;
#else
DWORD dwAclLength;
PSID pAuthenticatedUsersSID = NULL;
PACL pDACL = NULL;
BOOL bResult = FALSE;
PACCESS_ALLOWED_ACE pACE = NULL;
SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY;
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
__try
{
// initialize the security descriptor
if (!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION))
{
printf("InitializeSecurityDescriptor() failed with error %d\n",
GetLastError());
__leave;
}
// obtain a sid for the Authenticated Users Group
if (!AllocateAndInitializeSid(&siaNT, 1,
SECURITY_AUTHENTICATED_USER_RID, 0, 0, 0, 0, 0, 0, 0,
&pAuthenticatedUsersSID))
{
printf("AllocateAndInitializeSid() failed with error %d\n",
GetLastError());
__leave;
}
// NOTE:
//
// The Authenticated Users group includes all user accounts that
// have been successfully authenticated by the system. If access
// must be restricted to a specific user or group other than
// Authenticated Users, the SID can be constructed using the
// LookupAccountSid() API based on a user or group name.
// calculate the DACL length
dwAclLength = sizeof(ACL)
// add space for Authenticated Users group ACE
+ sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)
+ GetLengthSid(pAuthenticatedUsersSID);
// allocate memory for the DACL
pDACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
dwAclLength);
if (!pDACL)
{
printf("HeapAlloc() failed with error %d\n", GetLastError());
__leave;
}
// initialize the DACL
if (!InitializeAcl(pDACL, dwAclLength, ACL_REVISION))
{
printf("InitializeAcl() failed with error %d\n",
GetLastError());
__leave;
}
// add the Authenticated Users group ACE to the DACL with
// GENERIC_READ, GENERIC_WRITE, and GENERIC_EXECUTE access
if (!AddAccessAllowedAce(pDACL, ACL_REVISION,
GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
pAuthenticatedUsersSID))
{
printf("AddAccessAllowedAce() failed with error %d\n",
GetLastError());
__leave;
}
// set the DACL in the security descriptor
if (!SetSecurityDescriptorDacl(pSD, TRUE, pDACL, FALSE))
{
printf("SetSecurityDescriptorDacl() failed with error %d\n",
GetLastError());
__leave;
}
bResult = TRUE;
} __finally
{
if (pAuthenticatedUsersSID)
FreeSid(pAuthenticatedUsersSID);
}
if (bResult == FALSE)
{
if (pDACL)
HeapFree(GetProcessHeap(), 0, pDACL);
pDACL = NULL;
}
return (void*) pDACL;
#endif // ends Windows code
}
// The following function frees memory allocated in the
// BuildRestrictedSD() function
void CDataTransferUser::FreeRestrictedSD(void* ptr)
{
#ifndef LINUX
if (ptr)
HeapFree(GetProcessHeap(), 0, ptr);
#endif
return;
}
////////////////////////////////////////////////////////////////////////////
//////////////////////
// CDataTransferServer
//==========================================================================
======================
CDataTransferServer::CDataTransferServer()
{
m_nCameraID = 0;
m_nFileMapSize = 0;
m_nMaxFrames = 0;
m_nMaxConfigSize = 0;
m_nConfigBlocks = 0;
m_bKeyBlock = false;
m_nMaxDataSize = 0;
m_nControlSize = 0;
m_nUserReferenceCount = 0;
m_szObjNameSuffix[0] = '\0';
m_nLastSendTime = 0;
m_nDistanceFromKeyData = 0;
m_nLastErrorLoggedIgnoreFrames = 0;
m_nPFramesIgnored = 0;
#ifndef LINUX
::InitializeCriticalSectionAndSpinCount(&m_lockEvents, 0x80000400);
#else
pthread_mutexattr_t mutexattr;
pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_mutex_init(&m_lockEvents,&mutexattr);
#endif
}
//==========================================================================
======================
CDataTransferServer::~CDataTransferServer()
{
// Close all of the events
#ifndef LINUX
::EnterCriticalSection(&m_lockEvents);
#else
pthread_mutex_lock(&m_lockEvents);
#endif
while (m_mapUserEvents.size() > 0)
{
::CloseHandle(m_mapUserEvents.begin()->second.hEvent);
printf("before m_mapUserEvents erase size() =
%d\n",m_mapUserEvents.size());
m_mapUserEvents.erase(m_mapUserEvents.begin());
printf("after m_mapUserEvents erase size() =
%d\n",m_mapUserEvents.size());
}
#ifndef LINUX
::LeaveCriticalSection(&m_lockEvents);
#else
pthread_mutex_unlock(&m_lockEvents);
printf("pthread_mutex_unlock\n");
#endif
#ifndef LINUX
::DeleteCriticalSection(&m_lockEvents);
#else
pthread_mutex_destroy(&m_lockEvents);
printf("pthread_mutex_destroy\n");
#endif
}
//==========================================================================
======================
bool CDataTransferServer::AddUser(unsigned int nUserID, std::wstring&
strMemoryName,
std::wstring&
strMutexName, std::wstring& strEventName)
{
printf("AddUser\n");
#ifndef LINUX
::EnterCriticalSection(&m_lockEvents);
#else
pthread_mutex_lock(&m_lockEvents);
#endif
if (m_mapUserEvents.find(nUserID) == m_mapUserEvents.end())
{
++m_nUserReferenceCount;
UserEventInfo ei;
ei.strEventName = L"Global\\SmartCamEvent";
#ifdef LINUX
wchar_t arg[512];
mbstowcs(arg,m_szObjNameSuffix,512);
ei.strEventName += arg;
#else
ei.strEventName += m_szObjNameSuffix;
#endif
printf("AddUser2\n");
#ifdef LINUX
wchar_t szUserID[16];
swprintf(szUserID, sizeof(szUserID) / sizeof(*szUserID) ,
L"_%x", nUserID);
ei.strEventName += szUserID;
#else
TCHAR szUserID[16];
wsprintf(szUserID, L"_%x", nUserID);
ei.strEventName += szUserID;
#endif
#ifndef LINUX
SECURITY_ATTRIBUTES sa;
LPSECURITY_ATTRIBUTES lpEventAttributes = &sa;
SECURITY_DESCRIPTOR sd;
sa.nLength = sizeof sa;
sa.bInheritHandle = FALSE;
sa.lpSecurityDescriptor = &sd;
void* pDACL = BuildRestrictedSD(&sd);
if (pDACL == NULL)
lpEventAttributes = NULL;
ei.hEvent = CreateEvent(lpEventAttributes, FALSE, FALSE,
ei.strEventName.c_str());
#else
ei.hEvent = CreateEvent(NULL, false, false,
ei.strEventName.c_str());
printf("AddUser3\n");
#endif
ei.nLastEventConsumedTime = 0;
#ifndef LINUX
if (pDACL)
FreeRestrictedSD(pDACL);
#endif
m_mapUserEvents[nUserID] = ei;
}
strEventName = m_mapUserEvents[nUserID].strEventName;
strMemoryName = m_strMemoryName;
strMutexName = m_strMutexName;
printf("AddUser4\n");
#ifndef LINUX
::LeaveCriticalSection(&m_lockEvents);
#else
pthread_mutex_unlock(&m_lockEvents);
#endif
return true;
}
//==========================================================================
======================
bool CDataTransferServer::RemoveUser(unsigned int nUserID)
{
#ifndef LINUX
::EnterCriticalSection(&m_lockEvents);
#else
pthread_mutex_lock(&m_lockEvents);
#endif
CUserEventMap::iterator itEvent = m_mapUserEvents.find(nUserID);
if (itEvent != m_mapUserEvents.end())
{
if (m_nUserReferenceCount > 0)
--m_nUserReferenceCount;
::CloseHandle(itEvent->second.hEvent);
m_mapUserEvents.erase(itEvent);
}
#ifndef LINUX
::LeaveCriticalSection(&m_lockEvents);
#else
pthread_mutex_unlock(&m_lockEvents);
#endif
return true;
}
//==========================================================================
======================
bool CDataTransferServer::Initialize(int nCameraID, CC_SAMPLETYPE
nDataType,
unsigned
int nImageWidth, unsigned int nImageHeight,
unsigned
int nMaxFrames)
{
bool bOkay = true;
char buffer[64] = {0};
// This is going to be a problem if we try to re-initialize with a
different image size...
if (m_bInitialized)
return true;
m_nCameraID = nCameraID;
m_nMaxFrames = nMaxFrames;
if (m_nMaxFrames < 2)
m_nMaxFrames = 2;
// Calculate how much space we need for the data and headers
m_nMaxDataSize = 0;
m_nMaxConfigSize = 0;
m_nConfigBlocks = 0;
if (((nDataType & CC_SAMPLETYPE_MPEG4) == CC_SAMPLETYPE_MPEG4) ||
((nDataType & CC_SAMPLETYPE_MPEG4AVC) == CC_SAMPLETYPE_MPEG4AVC))
{
m_nMaxDataSize = (nImageWidth * nImageHeight) + 1024; // for
VideoFrame size and motion data
m_nMaxConfigSize = 1024;
m_nConfigBlocks = 1;
m_bKeyBlock = true;
}
else if (nDataType == CC_SAMPLETYPE_UNCOMPRESSEDVIDEO_YUY2)
{
m_nMaxDataSize = (nImageWidth * nImageHeight * 2) + 1024; //
for VideoFrame size and motion data
m_nMaxConfigSize = 0;
}
else if (nDataType == CC_SAMPLETYPE_MJPEG)
{
m_nMaxDataSize = (nImageWidth * nImageHeight) + 1024; // for
VideoFrame size and motion data
m_nMaxConfigSize = 0;
}
m_nMaxFrames += m_bKeyBlock ? 1 : 0;
m_nMaxDataSize += 4 + sizeof(uTypeSpecificSize);
m_nControlSize = sizeof(CDataTransferControl);
// Control Block
m_nControlSize += (m_nMaxFrames - 1) *
sizeof(CDataTransferBlockHeader); // Data Block Headers
if (m_nMaxConfigSize > 0)
m_nControlSize += sizeof(CDataTransferBlockHeader);
// Make sure the control size is DWORD-aligned
while ((m_nControlSize & 0x03) != 0)
++m_nControlSize;
m_nFileMapSize = m_nControlSize + m_nMaxFrames * m_nMaxDataSize;
// Data Blocks
if (m_nMaxConfigSize > 0)
m_nFileMapSize += m_nMaxConfigSize;
// Config Header & Config Data
// Suffix for global objects (file map and sync objects) based on
camera ID and data type
#ifdef LINUX
sprintf(m_szObjNameSuffix, "_%x_%x", nCameraID, nDataType);
#else
::swprintf_s(m_szObjNameSuffix, 31, L"_%x_%x", nCameraID,
nDataType);
#endif
#ifndef LINUX
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
sa.nLength = sizeof sa;
sa.bInheritHandle = FALSE;
sa.lpSecurityDescriptor = &sd;
void* pDACL = BuildRestrictedSD(&sd);
if (pDACL == NULL)
bOkay = false;
#endif
if (bOkay)
{
if (m_hMutexControl == NULL)
{
m_strMutexName = L"Global\\SmartCamMutex";
#ifdef LINUX
m_hMutexControl = sem_open(buffer, O_CREAT, 0600,
0);
#else
m_hMutexControl = ::CreateMutex(&sa, TRUE,
m_strMutexName.c_str());
#endif
if (m_hMutexControl == NULL)
bOkay = false;
}
}
#ifdef LINUX
if (bOkay)
{
char buffer[256];
wcstombs(buffer,m_strMemoryName.c_str(),256);
FILE* stream = fopen(buffer, "rw");
int fd = fileno(stream);
m_pControl = (CDataTransferControl*)mmap(NULL,
m_nFileMapSize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if (m_pControl)
{
memset(m_pControl, 0, m_nControlSize);
m_pControl->nConfigurationBlock = 0xffffffff;
m_pControl->nNewestKeyDataBlock = 0xffffffff;
m_pControl->nNewestDataBlock = 0xffffffff;
m_pControl->nBlockHeaders = m_nMaxFrames +
m_nConfigBlocks;
m_pControl->nTimeOfLastClientAccess = ::GetTickCount();
}
else
bOkay = false;
}
#else
if (bOkay)
{
if (m_hSharedMemory == NULL || m_hSharedMemory ==
INVALID_HANDLE_VALUE)
{
m_strMemoryName = L"Global\\SmartCamMem";
m_strMemoryName += m_szObjNameSuffix;
#ifdef LINUX
m_hSharedMemory =
#else
m_hSharedMemory =
::CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE,
#endif
0,, m_strMemoryName.c_str());
if (m_hSharedMemory == NULL || m_hSharedMemory ==
INVALID_HANDLE_VALUE)
bOkay = false;
}
}
if (bOkay)
{
if (m_pControl == NULL)
{
m_pControl =
(CDataTransferControl*)::MapViewOfFile(m_hSharedMemory,
FILE_MAP_ALL_ACCESS, 0, 0, m_nFileMapSize);
if (m_pControl)
{
::ZeroMemory(m_pControl, m_nControlSize);
m_pControl->nConfigurationBlock = 0xffffffff;
m_pControl->nNewestKeyDataBlock = 0xffffffff;
m_pControl->nNewestDataBlock = 0xffffffff;
m_pControl->nBlockHeaders = m_nMaxFrames +
m_nConfigBlocks;
m_pControl->nTimeOfLastClientAccess =
::GetTickCount();
}
else
bOkay = false;
}
}
#endif
#ifndef LINUX
if (pDACL)
FreeRestrictedSD(pDACL);
#endif
if (m_hMutexControl)
#ifndef LINUX
::ReleaseMutex(m_hMutexControl);
#endif
m_bInitialized = bOkay;
return bOkay;
}
//===========================================================:==============
=======================
bool CDataTransferServer::SendData(CVideoFrame *frame)
{
bool bFrameSent = false;
if (!m_bInitialized) return false;
if(frame == NULL) return false;
static DWORD dwWaitTime = 0;
static DWORD dwFramesSent = 0;
static DWORD dwFramesSkipped = 0;
bool bShowStats = false;
if (frame->GetSize() > m_nMaxDataSize)
{
#ifndef LINUX
::OutputDebugString(L"CDataTransferServer::SendData: Data
exceeds available size; data not posted to memory\n");
#else
cerr << "CDataTransferServer::SendData: Data exceeds available
size; data not posted to memory" << endl;
#endif
return false;
}
if (CheckPFrameCount(frame) == false)
return false;
// Wait for up to 25ms to lock the memory. That's a little shorter
than 1/30th of a
// second, which is our fastest video frame rate.
DWORD dwTimeStart = ::GetTickCount();
DWORD dwWait = ::WaitForSingleObject(m_hMutexControl, 25);
#ifndef LINUX
if (dwWait == WAIT_OBJECT_0 || dwWait == WAIT_ABANDONED)
#else
if (dwWait == WAIT_OBJECT_0)
#endif
{
DWORD dwTimeNow = ::GetTickCount();
dwWaitTime += dwTimeNow - dwTimeStart;
++dwFramesSent;
bShowStats = (dwTimeNow - dwTimeStart != 0);
unsigned long nBlock, nOffset;
bool bOkayToSendFrame = true;
unsigned long nNormalStartBlock = m_nConfigBlocks +
(m_bKeyBlock ? 1 : 0);
bool bCurrentKeyBlock = false;
// Wrap this section in try/except to handle exceptions thrown
by memory mapped file access
#ifndef LINUX
__try
#else
try
#endif
{
if (frame->GetType() == CC_SAMPLETYPE_MPEG4_CONFIG ||
frame->GetType() == CC_SAMPLETYPE_MPEG4AVC_CONFIG)
{
// Configuration data is always in block 0
nBlock = 0;
nOffset = 0;
m_pControl->nConfigurationBlock = nBlock;
}
else if ((frame->GetType() == CC_SAMPLETYPE_MPEG4_IFRAME
|| frame->GetType() == CC_SAMPLETYPE_MPEG4AVC_IFRAME) && m_bKeyBlock)
{
// Key data is always in the block after the
configuration block
// This block will be overwritten even if somebody
is using it. We should get
// key data infrequently enough so that this won't
be a problem.
bCurrentKeyBlock = true;
nBlock = m_nConfigBlocks;
nOffset = m_nMaxConfigSize + (nBlock -
m_nConfigBlocks) * m_nMaxDataSize;
m_pControl->nNewestKeyDataBlock = nBlock;
m_pControl->nNewestDataBlock = nBlock;
m_pControl->nTimeOfNewestKeyDataBlock = dwTimeNow;
m_pControl->nTimeOfNewestDataBlock = dwTimeNow;
}
else
{
// Normal data -- get the next block that is not
being read
bool bContinue = true;
nBlock = m_pControl->nNewestDataBlock;
unsigned long nStartBlock = nBlock;
do
{
if (m_pControl->nNewestDataBlock ==
0xffffffff) // First block?
{
nBlock = nNormalStartBlock;
bContinue = false;
}
else
{
++nBlock;
if (m_bKeyBlock && nBlock <
nNormalStartBlock || nBlock >= m_nMaxFrames + m_nConfigBlocks)
nBlock = nNormalStartBlock;
}
if
(m_pControl->aBlockHeaders[nBlock].nReaderReferenceCount == 0)
bContinue = false;
else
{
// This block is being read. Make sure
that the reader didn't timeout
static const DWORD nReaderTimeout =
30000;
DWORD dwElapsed;
if (dwTimeNow >=
m_pControl->aBlockHeaders[nBlock].nTimeOfLastRead)
dwElapsed = dwTimeNow -
m_pControl->aBlockHeaders[nBlock].nTimeOfLastRead;
else
{
// The time wrapped around back
to 0.
dwElapsed = 0xffffffff -
m_pControl->aBlockHeaders[nBlock].nTimeOfLastRead + dwTimeNow;
}
if (dwElapsed > nReaderTimeout)
{
// Read timed out, so we'll use
this block
m_pControl->aBlockHeaders[nBlock].nReaderReferenceCount = 0;
#ifndef LINUX
::OutputDebugString(L"CDataTransferServer: Releasing a block that was locked
for too long.\n");
#else
cerr << "CDataTransferServer:
Releasing a block that was locked for too long." << endl;
#endif
bContinue = false;
}
}
} while (bContinue && nBlock != nStartBlock);
// Did we find a good destination?
nOffset = m_nMaxConfigSize + (nBlock -
m_nConfigBlocks) * m_nMaxDataSize;
if
(m_pControl->aBlockHeaders[nBlock].nReaderReferenceCount == 0)
{
m_pControl->nNewestDataBlock = nBlock;
m_pControl->nTimeOfNewestDataBlock =
dwTimeNow;
}
else
bOkayToSendFrame = false;
}
// actual frame sent here
if (bOkayToSendFrame)
{
// Set the frame type into DataTransferControl
m_pControl->nSampleType = frame->GetType();
m_pControl->nDistanceFromKeyData =
frame->m_nDistanceFromKeyData;
// Set the header info for this block
//DWORD dwTimeNow = ::GetTickCount();
if (m_bKeyBlock)
{
if ((bCurrentKeyBlock) || (nBlock ==
m_pControl->nConfigurationBlock))
m_nDistanceFromKeyData = 0;
else
++m_nDistanceFromKeyData;
}
else
{ // MJPEG
m_nDistanceFromKeyData = 0;
}
nOffset += m_nControlSize;
m_pControl->aBlockHeaders[nBlock].nReaderReferenceCount = 0;
m_pControl->aBlockHeaders[nBlock].nDistanceFromKeyData =
m_nDistanceFromKeyData;
//m_pControl->aBlockHeaders[nBlock].nDistanceFromKeyData =
frame->m_nDistanceFromKeyData;
m_pControl->aBlockHeaders[nBlock].nDataOffset =
nOffset;
m_pControl->aBlockHeaders[nBlock].nDataType =
(unsigned long)frame->GetType();
m_pControl->aBlockHeaders[nBlock].nDataSize =
sizeof(DWORD) + frame->GetSize();
m_pControl->aBlockHeaders[nBlock].nTimeOfWrite =
dwTimeNow;
m_pControl->aBlockHeaders[nBlock].nTimeOfLastRead =
dwTimeNow;
// Write an offset to the real data -- 4 bytes
unsigned long nStartOfDataSize = 4;
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &nStartOfDataSize, nStartOfDataSize);
nOffset += 4;
// write frame header
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_type, sizeof(int)); // we have it header - send it
again anyway
nOffset += sizeof(int);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_width, sizeof(int));
nOffset += sizeof(int);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_height, sizeof(int));
nOffset += sizeof(int);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_dataLength, sizeof(long));
nOffset += sizeof(long);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_motionLength, sizeof(long));
nOffset += sizeof(long);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_motionWidth, sizeof(long));
nOffset += sizeof(long);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_motionHeight, sizeof(long));
nOffset += sizeof(long);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_record, sizeof(int));
nOffset += sizeof(int);
// write trigger
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_trigger, sizeof(int));
nOffset += sizeof(int);
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, &frame->m_time, sizeof(__int64));
nOffset += sizeof(__int64);
// write motion block
if(frame->m_motionLength > 0)
{
::memcpy_s(((unsigned char*)m_pControl) +
nOffset, m_nMaxDataSize, frame->m_motion, frame->m_motionLength);
nOffset += frame->m_motionLength;
}
// write data
::memcpy_s(((unsigned char*)m_pControl) + nOffset,
m_nMaxDataSize, frame->m_data, frame->m_dataLength);
nOffset += frame->m_dataLength;
// we done
bFrameSent = true;
m_nLastSendTime = dwTimeNow;
}
}
#ifndef LINUX
__except (::GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ?
EXCEPTION_EXECUTE_HANDLER :
EXCEPTION_CONTINUE_SEARCH)
#else
catch(std::exception& e)
#endif
{
// Access to memory mapped file caused an exception
}
// Updated data is ready for clients
if (bFrameSent)
SetNewDataEvents();
#ifndef LINUX
::ReleaseMutex(m_hMutexControl);
#else
sem_close(m_hMutexControl);
#endif
}
else
{
++dwFramesSkipped;
bShowStats = true;
}
if (bShowStats)
{
wchar_t szMsg[128];
#ifdef LINUX
::swprintf(szMsg, 128, L"DataServer: %d frames sent (wait=%0.2f
ms), %d frames skipped\n", dwFramesSent, dwWaitTime / (double)dwFramesSent,
dwFramesSkipped);
#else
::swprintf_s(szMsg, L"DataServer: %d frames sent (wait=%0.2f
ms), %d frames skipped\n", dwFramesSent, dwWaitTime / (double)dwFramesSent,
dwFramesSkipped);
#endif
#ifndef LINUX
::OutputDebugString(szMsg);
#else
cerr << szMsg << endl;
#endif
}
return bFrameSent;
}
bool CDataTransferServer::CheckPFrameCount(CVideoFrame *frame)
{
if ((frame->GetType() == CC_SAMPLETYPE_MPEG4_PFRAME) ||
(frame->GetType() == CC_SAMPLETYPE_MPEG4AVC_PFRAME))
{
if (frame->m_nDistanceFromKeyData > (m_nMaxFrames - 2))
// 2 = IFrame + Config Block
{ // We received more P frames than we are expecting,
#ifndef LINUX
::OutputDebugString(L"CDataTransferServer::SendData:
received more P frames than expected, ignoring the frames\n");
#else
cerr << "CDataTransferServer::SendData: received more P
frames than expected, ignoring the frames" << endl;
#endif
m_nPFramesIgnored ++;
//DWORD dwNow = ::GetTickCount();
//if(dwNow - m_nLastErrorLoggedIgnoreFrames > 1000*60*60)
// don't log too often - once in hour
//{
// m_nLastErrorLoggedIgnoreFrames = dwNow;
// try
// {
// CLogFile* pLogFile = new
CLogFile(L"SmartCamXi_NVR_Recorder.log", TRUE);
// if(pLogFile != NULL)
// {
// TCHAR tmp[MAX_PATH];
// _stprintf(tmp, L"Ignoring P Frames -
I Frame Interval is not set correctly - CameraControlLib: Camera ID: %d,
Expected I Frame Interval: %d \n", m_nCameraID, m_nMaxFrames - 2);
// pLogFile->Write(tmp);
// delete pLogFile;
// }
// }
// catch (...)
// {
// }
// m_nPFramesIgnored = 0;
//}
return false;
}
}
return true;
}
//==========================================================================
======================
void CDataTransferServer::SetNewDataEvents()
{
DWORD dwNow = ::GetTickCount();
unsigned int nRemoveThisID = 0xffffffff;
#ifndef LINUX
::EnterCriticalSection(&m_lockEvents);
#else
pthread_mutex_lock(&m_lockEvents);
#endif
CUserEventMap::iterator itEvent = m_mapUserEvents.begin();
while (itEvent != m_mapUserEvents.end())
{
// Check to see if the previous event has been consumed
if (::WaitForSingleObject(itEvent->second.hEvent, 0) ==
WAIT_OBJECT_0)
{
// It hasn't -- make sure it hasn't been inactive for too
long
DWORD dwElapsed;
if (itEvent->second.nLastEventConsumedTime == 0)
{
// This event hasn't been set yet, so don't try to
check the time
dwElapsed = 0;
}
else if (dwNow >= itEvent->second.nLastEventConsumedTime)
dwElapsed = dwNow -
itEvent->second.nLastEventConsumedTime;
else
{
// The time wrapped around back to 0.
dwElapsed = 0xffffffff -
itEvent->second.nLastEventConsumedTime + dwNow;
}
if (dwElapsed > 300000) // 5 minute timeout
nRemoveThisID = itEvent->first;
}
else
itEvent->second.nLastEventConsumedTime = dwNow;
::SetEvent(itEvent->second.hEvent);
++itEvent;
}
// Remove one user if the event has timed out. This will only remove
one user each
// time in this function, but this is called frequently.
if (nRemoveThisID != 0xffffffff)
RemoveUser(nRemoveThisID);
#ifndef LINUX
::LeaveCriticalSection(&m_lockEvents);
#else
pthread_mutex_lock(&m_lockEvents);
#endif
}
extern "C"
{
int func() /* THIS IS WHERE THE PROBLEM IS */
{
wchar_t memoryName[256];
wchar_t mutexName[256];
wchar_t eventName[256];
mbstowcs(memoryName, "MemoryName", 256);
mbstowcs(mutexName, "MutexName", 256);
mbstowcs(eventName, "EventName", 256);
std::wstring memoryString(memoryName);
std::wstring mutexString(mutexName);
std::wstring eventString(eventName);
CDataTransferServer *srv = new CDataTransferServer();
srv->Initialize(1, CC_SAMPLETYPE_MPEG4,128,256,64);
printf("Inside entry point tester 1\n");
srv->AddUser(5, memoryString, mutexString, eventString);
printf("Inside entry point tester 2\n");
delete srv;
printf("Exiting entry point tester \n");
/* THIS IS WHERE THE PROBLEM IS */
}
}
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]