2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Access Method
|
2003-09-25 13:49:12 +02:00
|
|
|
* MODULE: isc_sync.cpp
|
2012-11-01 12:40:18 +01:00
|
|
|
* DESCRIPTION: OS-dependent IPC: shared memory, mutex and event.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Interbase Public
|
|
|
|
* License Version 1.0 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy
|
|
|
|
* of the License at http://www.Inprise.com/IPL.html
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an
|
|
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
|
|
|
* or implied. See the License for the specific language governing
|
|
|
|
* rights and limitations under the License.
|
|
|
|
*
|
|
|
|
* The Original Code was created by Inprise Corporation
|
|
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
|
|
* Copyright (C) Inprise Corporation.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
2002-02-16 03:50:01 +01:00
|
|
|
*
|
|
|
|
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "XENIX" port
|
2002-02-16 04:05:21 +01:00
|
|
|
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "DELTA" port
|
2002-02-16 04:27:33 +01:00
|
|
|
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "IMP" port
|
2002-02-16 03:50:01 +01:00
|
|
|
*
|
2002-02-23 23:15:24 +01:00
|
|
|
* 2002-02-23 Sean Leyne - Code Cleanup, removed old M88K and NCR3000 port
|
|
|
|
*
|
2002-10-28 05:42:54 +01:00
|
|
|
* 2002.10.27 Sean Leyne - Completed removal of obsolete "DG_X86" port
|
2002-10-28 05:44:59 +01:00
|
|
|
* 2002.10.27 Sean Leyne - Completed removal of obsolete "M88K" port
|
2002-10-28 05:42:54 +01:00
|
|
|
*
|
2002-10-29 03:45:09 +01:00
|
|
|
* 2002.10.28 Sean Leyne - Completed removal of obsolete "DGUX" port
|
2002-10-29 04:17:45 +01:00
|
|
|
* 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "DecOSF" port
|
2002-10-29 04:31:20 +01:00
|
|
|
* 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "SGI" port
|
2002-10-29 03:45:09 +01:00
|
|
|
*
|
2002-10-30 07:40:58 +01:00
|
|
|
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
|
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
2001-07-29 19:42:23 +02:00
|
|
|
#include "firebird.h"
|
2004-04-29 00:43:34 +02:00
|
|
|
#include <stdio.h>
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2003-03-04 04:42:23 +01:00
|
|
|
#ifdef SOLARIS
|
2010-10-13 12:39:52 +02:00
|
|
|
#include "../common/gdsassert.h"
|
2003-03-04 04:42:23 +01:00
|
|
|
#endif
|
|
|
|
|
2007-11-12 16:18:49 +01:00
|
|
|
#ifdef HPUX
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <sys/pstat.h>
|
|
|
|
#endif
|
|
|
|
|
2003-11-11 13:19:20 +01:00
|
|
|
#include "gen/iberror.h"
|
2010-10-12 10:02:57 +02:00
|
|
|
#include "../yvalve/gds_proto.h"
|
|
|
|
#include "../common/isc_proto.h"
|
|
|
|
#include "../common/os/isc_i_proto.h"
|
|
|
|
#include "../common/os/os_utils.h"
|
|
|
|
#include "../common/isc_s_proto.h"
|
2010-10-13 12:39:52 +02:00
|
|
|
#include "../common/file_params.h"
|
|
|
|
#include "../common/gdsassert.h"
|
2004-10-15 00:11:43 +02:00
|
|
|
#include "../common/config/config.h"
|
2007-02-20 16:39:01 +01:00
|
|
|
#include "../common/utils_proto.h"
|
2008-08-27 14:20:47 +02:00
|
|
|
#include "../common/StatusArg.h"
|
2011-10-13 13:31:15 +02:00
|
|
|
#include "../common/ThreadData.h"
|
2012-11-01 12:40:18 +01:00
|
|
|
#include "../common/classes/rwlock.h"
|
|
|
|
#include "../common/classes/GenericMap.h"
|
|
|
|
#include "../common/classes/RefMutex.h"
|
|
|
|
#include "../common/classes/array.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
static int process_id;
|
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// Unix specific stuff
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef UNIX
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
|
2002-11-04 10:04:18 +01:00
|
|
|
#ifdef HAVE_SYS_SIGNAL_H
|
|
|
|
#include <sys/signal.h>
|
2002-11-01 14:21:17 +01:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#include <errno.h>
|
2002-08-22 12:48:26 +02:00
|
|
|
#ifdef HAVE_UNISTD_H
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <unistd.h>
|
2002-08-22 12:48:26 +02:00
|
|
|
#endif
|
2009-06-10 12:26:17 +02:00
|
|
|
|
|
|
|
#ifdef USE_SYS5SEMAPHORE
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <sys/ipc.h>
|
|
|
|
#include <sys/shm.h>
|
|
|
|
#include <sys/sem.h>
|
2011-10-13 13:31:15 +02:00
|
|
|
#include <sys/time.h>
|
2009-06-10 12:26:17 +02:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-12-11 11:59:26 +01:00
|
|
|
#ifdef HAVE_FCNTL_H
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <fcntl.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
|
|
|
#define FTOK_KEY 15
|
|
|
|
#define PRIV 0666
|
|
|
|
|
2009-06-02 08:27:23 +02:00
|
|
|
//#ifndef SHMEM_DELTA
|
|
|
|
//#define SHMEM_DELTA (1 << 22)
|
|
|
|
//#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-06-02 08:27:23 +02:00
|
|
|
//#ifndef SIGURG
|
|
|
|
//#define SIGURG SIGINT
|
|
|
|
//#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-28 13:27:18 +01:00
|
|
|
#endif // UNIX
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-07-06 07:32:02 +02:00
|
|
|
#ifdef HAVE_SYS_PARAM_H
|
2002-07-02 11:49:19 +02:00
|
|
|
#include <sys/param.h>
|
2002-07-06 07:32:02 +02:00
|
|
|
#endif
|
|
|
|
|
2002-10-16 10:38:04 +02:00
|
|
|
#ifndef HAVE_GETPAGESIZE
|
2008-12-20 09:12:19 +01:00
|
|
|
static size_t getpagesize()
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
|
|
|
return PAGESIZE;
|
|
|
|
}
|
2002-10-16 10:38:04 +02:00
|
|
|
#endif
|
2002-07-02 11:49:19 +02:00
|
|
|
|
2011-10-13 13:31:15 +02:00
|
|
|
//#define DEBUG_IPC
|
2008-10-10 17:58:05 +02:00
|
|
|
#ifdef DEBUG_IPC
|
|
|
|
#define IPC_TRACE(x) { /*time_t t; time(&t); printf("%s", ctime(&t) ); printf x; fflush (stdout);*/ gds__log x; }
|
|
|
|
#else
|
|
|
|
#define IPC_TRACE(x)
|
|
|
|
#endif
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// Windows NT
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef WIN_NT
|
|
|
|
|
|
|
|
#include <process.h>
|
|
|
|
#include <windows.h>
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2008-08-27 14:20:47 +02:00
|
|
|
using namespace Firebird;
|
2004-03-20 15:57:40 +01:00
|
|
|
|
2009-12-06 02:34:57 +01:00
|
|
|
static void error(Arg::StatusVector&, const TEXT*, ISC_STATUS);
|
2012-11-02 17:27:12 +01:00
|
|
|
static bool event_blocked(const event_t* event, const SLONG value);
|
2003-03-01 13:29:22 +01:00
|
|
|
|
|
|
|
#ifdef UNIX
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2009-01-13 15:29:07 +01:00
|
|
|
static GlobalPtr<Mutex> openFdInit;
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
class DevNode
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
DevNode()
|
|
|
|
: f_dev(0), f_ino(0)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
DevNode(dev_t d, ino_t i)
|
|
|
|
: f_dev(d), f_ino(i)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
DevNode(const DevNode& v)
|
|
|
|
: f_dev(v.f_dev), f_ino(v.f_ino)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
dev_t f_dev;
|
|
|
|
ino_t f_ino;
|
|
|
|
|
|
|
|
bool operator==(const DevNode& v) const
|
|
|
|
{
|
|
|
|
return f_dev == v.f_dev && f_ino == v.f_ino;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator>(const DevNode& v) const
|
|
|
|
{
|
|
|
|
return f_dev > v.f_dev ? true :
|
|
|
|
f_dev < v.f_dev ? false :
|
|
|
|
f_ino > v.f_ino;
|
|
|
|
}
|
|
|
|
|
|
|
|
const DevNode& operator=(const DevNode& v)
|
|
|
|
{
|
|
|
|
f_dev = v.f_dev;
|
|
|
|
f_ino = v.f_ino;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-11-02 17:27:12 +01:00
|
|
|
namespace Firebird {
|
|
|
|
|
|
|
|
class CountedRWLock
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CountedRWLock()
|
|
|
|
: sharedAccessCounter(0)
|
|
|
|
{ }
|
|
|
|
RWLock rwlock;
|
|
|
|
AtomicCounter cnt;
|
|
|
|
Mutex sharedAccessMutex;
|
|
|
|
int sharedAccessCounter;
|
|
|
|
};
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
class CountedFd
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CountedFd(int f)
|
|
|
|
: fd(f), useCount(0)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
~CountedFd()
|
|
|
|
{
|
|
|
|
fb_assert(useCount == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int fd;
|
|
|
|
int useCount;
|
|
|
|
|
|
|
|
private:
|
|
|
|
CountedFd(const CountedFd&);
|
|
|
|
const CountedFd& operator=(const CountedFd&);
|
|
|
|
};
|
|
|
|
|
2012-11-02 17:27:12 +01:00
|
|
|
} // namespace Firebird
|
2012-11-01 12:40:18 +01:00
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
namespace {
|
|
|
|
|
2012-11-02 17:27:12 +01:00
|
|
|
typedef GenericMap<Pair<Left<string, Firebird::CountedRWLock*> > > RWLocks;
|
2012-11-01 12:40:18 +01:00
|
|
|
GlobalPtr<RWLocks> rwlocks;
|
|
|
|
GlobalPtr<Mutex> rwlocksMutex;
|
|
|
|
#ifdef USE_FCNTL
|
|
|
|
const char* NAME = "fcntl";
|
|
|
|
#else
|
|
|
|
const char* NAME = "flock";
|
|
|
|
#endif
|
|
|
|
|
|
|
|
class FileLockHolder
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
|
|
|
public:
|
2012-11-02 17:27:12 +01:00
|
|
|
FileLockHolder(FileLock* l)
|
2012-11-01 12:40:18 +01:00
|
|
|
: lock(l)
|
|
|
|
{
|
|
|
|
Arg::StatusVector status;
|
2012-11-02 17:27:12 +01:00
|
|
|
if (!lock->setlock(status, FileLock::FLM_EXCLUSIVE))
|
2012-11-01 12:40:18 +01:00
|
|
|
status.raise();
|
|
|
|
}
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
~FileLockHolder()
|
|
|
|
{
|
|
|
|
lock->unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2012-11-02 17:27:12 +01:00
|
|
|
FileLock* lock;
|
2012-11-01 12:40:18 +01:00
|
|
|
};
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-02 17:27:12 +01:00
|
|
|
DevNode getNode(const char* name)
|
2012-11-01 12:40:18 +01:00
|
|
|
{
|
|
|
|
struct stat statistics;
|
|
|
|
if (stat(name, &statistics) != 0)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
if (errno == ENOENT)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
//file not found
|
2012-11-02 17:27:12 +01:00
|
|
|
return DevNode();
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
|
|
|
|
system_call_failed::raise("stat");
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
2012-11-02 17:27:12 +01:00
|
|
|
return DevNode(statistics.st_dev, statistics.st_ino);
|
2012-11-01 12:40:18 +01:00
|
|
|
}
|
|
|
|
|
2012-11-02 17:27:12 +01:00
|
|
|
DevNode getNode(int fd)
|
2012-11-01 12:40:18 +01:00
|
|
|
{
|
|
|
|
struct stat statistics;
|
|
|
|
if (fstat(fd, &statistics) != 0)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("stat");
|
|
|
|
}
|
2008-10-21 06:25:49 +02:00
|
|
|
|
2012-11-02 17:27:12 +01:00
|
|
|
return DevNode(statistics.st_dev, statistics.st_ino);
|
2012-11-01 12:40:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
|
2012-11-02 17:27:12 +01:00
|
|
|
typedef GenericMap<Pair<NonPooled<DevNode, Firebird::CountedFd*> > > FdNodes;
|
2012-11-01 12:40:18 +01:00
|
|
|
static GlobalPtr<Mutex> fdNodesMutex;
|
|
|
|
static GlobalPtr<FdNodes> fdNodes;
|
|
|
|
|
|
|
|
FileLock::FileLock(const char* fileName, InitFunction* init)
|
|
|
|
: level(LCK_NONE), oFile(NULL),
|
|
|
|
#ifdef USE_FCNTL
|
|
|
|
lStart(0),
|
2003-10-30 10:49:40 +01:00
|
|
|
#endif
|
2012-11-01 12:40:18 +01:00
|
|
|
rwcl(NULL)
|
|
|
|
{
|
|
|
|
MutexLockGuard g(fdNodesMutex);
|
|
|
|
|
|
|
|
DevNode id(getNode(fileName));
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (id.f_ino)
|
|
|
|
{
|
|
|
|
CountedFd** got = fdNodes->get(id);
|
|
|
|
if (got)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
oFile = *got;
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!oFile)
|
|
|
|
{
|
|
|
|
int fd = os_utils::openCreateSharedFile(fileName, 0);
|
|
|
|
oFile = FB_NEW(*getDefaultMemoryPool()) CountedFd(fd);
|
|
|
|
CountedFd** put = fdNodes->put(getNode(fd));
|
|
|
|
fb_assert(put);
|
|
|
|
*put = oFile;
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (init)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
init(fd);
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
rwcl = getRw();
|
|
|
|
++(oFile->useCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_FILELOCKS
|
|
|
|
FileLock::FileLock(const FileLock* main, int s)
|
|
|
|
: level(LCK_NONE), oFile(main->oFile),
|
|
|
|
lStart(s), rwcl(getRw())
|
|
|
|
{
|
|
|
|
MutexLockGuard g(fdNodesMutex);
|
|
|
|
++(oFile->useCount);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
FileLock::~FileLock()
|
|
|
|
{
|
|
|
|
unlock();
|
|
|
|
|
|
|
|
{ // guard scope
|
|
|
|
MutexLockGuard g(rwlocksMutex);
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (--(rwcl->cnt) == 0)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
rwlocks->remove(getLockId());
|
|
|
|
delete rwcl;
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
}
|
|
|
|
{ // guard scope
|
|
|
|
MutexLockGuard g(fdNodesMutex);
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (--(oFile->useCount) == 0)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
fdNodes->remove(getNode(oFile->fd));
|
|
|
|
close(oFile->fd);
|
|
|
|
delete oFile;
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int FileLock::getFd()
|
|
|
|
{
|
|
|
|
return oFile->fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
int FileLock::setlock(const LockMode mode)
|
|
|
|
{
|
|
|
|
bool shared = true, wait = true;
|
2012-11-05 02:14:04 +01:00
|
|
|
switch (mode)
|
2012-11-01 12:40:18 +01:00
|
|
|
{
|
|
|
|
case FLM_TRY_EXCLUSIVE:
|
|
|
|
wait = false;
|
|
|
|
// fall through
|
|
|
|
case FLM_EXCLUSIVE:
|
|
|
|
shared = false;
|
|
|
|
break;
|
|
|
|
case FLM_TRY_SHARED:
|
|
|
|
wait = false;
|
|
|
|
// fall through
|
|
|
|
case FLM_SHARED:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
const LockLevel newLevel = shared ? LCK_SHARED : LCK_EXCL;
|
|
|
|
if (newLevel == level)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (level != LCK_NONE)
|
|
|
|
{
|
|
|
|
return wait ? EBUSY : -1;
|
|
|
|
}
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
// first take appropriate rwlock to avoid conflicts with other threads in our process
|
|
|
|
bool rc = true;
|
|
|
|
try
|
|
|
|
{
|
2012-11-05 02:14:04 +01:00
|
|
|
switch (mode)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
case FLM_TRY_EXCLUSIVE:
|
|
|
|
rc = rwcl->rwlock.tryBeginWrite();
|
|
|
|
break;
|
|
|
|
case FLM_EXCLUSIVE:
|
|
|
|
rwcl->rwlock.beginWrite();
|
|
|
|
break;
|
|
|
|
case FLM_TRY_SHARED:
|
|
|
|
rc = rwcl->rwlock.tryBeginRead();
|
|
|
|
break;
|
|
|
|
case FLM_SHARED:
|
|
|
|
rwcl->rwlock.beginRead();
|
|
|
|
break;
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
}
|
2012-11-05 02:14:04 +01:00
|
|
|
catch (const system_call_failed& fail)
|
2012-11-01 12:40:18 +01:00
|
|
|
{
|
|
|
|
return fail.getErrorCode();
|
|
|
|
}
|
|
|
|
if (!rc)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
// For shared lock we must take into an account reenterability
|
|
|
|
MutexEnsureUnlock guard(rwcl->sharedAccessMutex);
|
|
|
|
if (shared)
|
|
|
|
{
|
|
|
|
if (wait)
|
|
|
|
{
|
|
|
|
guard.enter();
|
|
|
|
}
|
|
|
|
else if (!guard.tryEnter())
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
return -1;
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
fb_assert(rwcl->sharedAccessCounter >= 0);
|
|
|
|
if (rwcl->sharedAccessCounter++ > 0)
|
|
|
|
{
|
|
|
|
// counter is non-zero - we already have file lock
|
|
|
|
level = LCK_SHARED;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#ifdef USE_FCNTL
|
|
|
|
// Take lock on a file
|
|
|
|
struct flock lock;
|
|
|
|
lock.l_type = shared ? F_RDLCK : F_WRLCK;
|
|
|
|
lock.l_whence = SEEK_SET;
|
|
|
|
lock.l_start = lStart;
|
|
|
|
lock.l_len = 1;
|
|
|
|
if (fcntl(oFile->fd, wait ? F_SETLKW : F_SETLK, &lock) == -1)
|
|
|
|
{
|
|
|
|
int rc = errno;
|
2012-11-05 02:14:04 +01:00
|
|
|
if (!wait && (rc == EACCES || rc == EAGAIN))
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
rc = -1;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (flock(oFile->fd, (shared ? LOCK_SH : LOCK_EX) | (wait ? 0 : LOCK_NB)))
|
|
|
|
{
|
|
|
|
int rc = errno;
|
2012-11-05 02:14:04 +01:00
|
|
|
if (!wait && (rc == EWOULDBLOCK))
|
2012-11-01 12:40:18 +01:00
|
|
|
{
|
|
|
|
rc = -1;
|
|
|
|
}
|
2008-10-10 17:58:05 +02:00
|
|
|
#endif
|
2012-11-01 12:40:18 +01:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (shared)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
rwcl->sharedAccessCounter--;
|
|
|
|
rwcl->rwlock.endRead();
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
else
|
|
|
|
rwcl->rwlock.endWrite();
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2012-11-05 02:14:04 +01:00
|
|
|
catch (const Exception&)
|
2012-11-01 12:40:18 +01:00
|
|
|
{ }
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
level = newLevel;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FileLock::setlock(Arg::StatusVector& status, const LockMode mode)
|
|
|
|
{
|
|
|
|
int rc = setlock(mode);
|
|
|
|
if (rc != 0)
|
|
|
|
{
|
|
|
|
if (rc > 0)
|
|
|
|
{
|
|
|
|
error(status, NAME, rc);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileLock::rwUnlock()
|
|
|
|
{
|
|
|
|
fb_assert(level != LCK_NONE);
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (level == LCK_SHARED)
|
|
|
|
rwcl->rwlock.endRead();
|
|
|
|
else
|
|
|
|
rwcl->rwlock.endWrite();
|
|
|
|
}
|
2012-11-05 02:14:04 +01:00
|
|
|
catch (const Exception& ex)
|
2012-11-01 12:40:18 +01:00
|
|
|
{
|
|
|
|
iscLogException("rwlock end-operation error", ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
level = LCK_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileLock::unlock()
|
|
|
|
{
|
|
|
|
if (level == LCK_NONE)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For shared lock we must take into an account reenterability
|
|
|
|
MutexEnsureUnlock guard(rwcl->sharedAccessMutex);
|
|
|
|
if (level == LCK_SHARED)
|
|
|
|
{
|
|
|
|
guard.enter();
|
|
|
|
|
|
|
|
fb_assert(rwcl->sharedAccessCounter > 0);
|
|
|
|
if (--(rwcl->sharedAccessCounter) > 0)
|
|
|
|
{
|
|
|
|
// counter is non-zero - we must keep file lock
|
|
|
|
rwUnlock();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_FCNTL
|
|
|
|
struct flock lock;
|
|
|
|
lock.l_type = F_UNLCK;
|
|
|
|
lock.l_whence = SEEK_SET;
|
|
|
|
lock.l_start = lStart;
|
|
|
|
lock.l_len = 1;
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (fcntl(oFile->fd, F_SETLK, &lock) != 0)
|
|
|
|
{
|
|
|
|
#else
|
|
|
|
if (flock(oFile->fd, LOCK_UN) != 0)
|
|
|
|
{
|
2008-10-10 17:58:05 +02:00
|
|
|
#endif
|
2012-11-01 12:40:18 +01:00
|
|
|
Arg::StatusVector local;
|
|
|
|
error(local, NAME, errno);
|
|
|
|
iscLogStatus("Unlock error", local.value());
|
|
|
|
}
|
|
|
|
|
|
|
|
rwUnlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
string FileLock::getLockId()
|
|
|
|
{
|
|
|
|
fb_assert(oFile);
|
|
|
|
|
|
|
|
DevNode id(getNode(oFile->fd));
|
|
|
|
|
|
|
|
const size_t len1 = sizeof(id.f_dev);
|
|
|
|
const size_t len2 = sizeof(id.f_ino);
|
|
|
|
#ifdef USE_FCNTL
|
|
|
|
const size_t len3 = sizeof(int);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
string rc(len1 + len2
|
|
|
|
#ifdef USE_FCNTL
|
|
|
|
+ len3
|
|
|
|
#endif
|
|
|
|
, ' ');
|
|
|
|
char* p = rc.begin();
|
|
|
|
|
|
|
|
memcpy(p, &id.f_dev, len1);
|
|
|
|
p += len1;
|
|
|
|
memcpy(p, &id.f_ino, len2);
|
|
|
|
#ifdef USE_FCNTL
|
|
|
|
p += len2;
|
|
|
|
memcpy(p, &lStart, len3);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
CountedRWLock* FileLock::getRw()
|
|
|
|
{
|
|
|
|
string id = getLockId();
|
|
|
|
CountedRWLock* rc = NULL;
|
|
|
|
|
|
|
|
MutexLockGuard g(rwlocksMutex);
|
|
|
|
|
|
|
|
CountedRWLock** got = rwlocks->get(id);
|
|
|
|
if (got)
|
|
|
|
{
|
|
|
|
rc = *got;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rc)
|
|
|
|
{
|
|
|
|
rc = FB_NEW(*getDefaultMemoryPool()) CountedRWLock;
|
|
|
|
CountedRWLock** put = rwlocks->put(id);
|
|
|
|
fb_assert(put);
|
|
|
|
*put = rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
++(rc->cnt);
|
|
|
|
|
|
|
|
return rc;
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#ifdef USE_SYS5SEMAPHORE
|
2011-10-13 13:31:15 +02:00
|
|
|
|
2012-06-22 13:39:24 +02:00
|
|
|
#ifndef HAVE_SEMUN
|
|
|
|
union semun
|
|
|
|
{
|
|
|
|
int val;
|
|
|
|
struct semid_ds *buf;
|
|
|
|
ushort *array;
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2009-12-06 02:34:57 +01:00
|
|
|
static SLONG create_semaphores(Arg::StatusVector&, SLONG, int);
|
2008-10-10 17:58:05 +02:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
int sharedCount = 0;
|
|
|
|
|
2009-06-06 20:13:57 +02:00
|
|
|
// this class is mapped into shared file
|
2008-10-10 17:58:05 +02:00
|
|
|
class SemTable
|
|
|
|
{
|
|
|
|
public:
|
2012-11-05 09:20:57 +01:00
|
|
|
const static int N_FILES = 128;
|
2008-10-10 17:58:05 +02:00
|
|
|
const static int N_SETS = 256;
|
2010-11-11 14:56:13 +01:00
|
|
|
#if defined(DEV_BUILD) || defined(FREEBSD)
|
|
|
|
const static int SEM_PER_SET = 4; // force multiple sets allocation || work with default freebsd kernel
|
2008-10-10 17:58:05 +02:00
|
|
|
#else
|
2008-10-21 06:25:49 +02:00
|
|
|
const static int SEM_PER_SET = 31; // hard limit for some old systems, might set to 32
|
2008-10-10 17:58:05 +02:00
|
|
|
#endif
|
|
|
|
const static unsigned char CURRENT_VERSION = 1;
|
|
|
|
unsigned char version;
|
|
|
|
|
|
|
|
private:
|
|
|
|
int lastSet;
|
|
|
|
|
2008-12-20 09:12:19 +01:00
|
|
|
struct
|
|
|
|
{
|
2008-10-10 17:58:05 +02:00
|
|
|
char name[MAXPATHLEN];
|
|
|
|
} filesTable[N_FILES];
|
|
|
|
|
2008-12-20 09:12:19 +01:00
|
|
|
struct
|
|
|
|
{
|
2008-10-10 17:58:05 +02:00
|
|
|
key_t semKey;
|
|
|
|
int fileNum;
|
|
|
|
SLONG mask;
|
|
|
|
|
|
|
|
int get(int fNum)
|
|
|
|
{
|
|
|
|
if (fileNum == fNum && mask != 0)
|
|
|
|
{
|
|
|
|
for (int bit = 0; bit < SEM_PER_SET; ++bit)
|
|
|
|
{
|
|
|
|
if (mask & (1 << bit))
|
|
|
|
{
|
|
|
|
mask &= ~(1 << bit);
|
|
|
|
return bit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// bad bits in mask ?
|
|
|
|
mask = 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int create(int fNum)
|
|
|
|
{
|
|
|
|
fileNum = fNum;
|
|
|
|
mask = 1 << SEM_PER_SET;
|
|
|
|
--mask;
|
|
|
|
mask &= ~1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void put(int bit)
|
|
|
|
{
|
|
|
|
// fb_assert(!(mask & (1 << bit)));
|
|
|
|
mask |= (1 << bit);
|
|
|
|
}
|
|
|
|
} set[N_SETS];
|
2008-10-21 06:25:49 +02:00
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
public:
|
|
|
|
void cleanup(int fNum, bool release);
|
|
|
|
|
2008-10-16 10:52:33 +02:00
|
|
|
key_t getKey(int semSet) const
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
|
|
|
fb_assert(semSet >= 0 && semSet < lastSet);
|
|
|
|
|
|
|
|
return set[semSet].semKey;
|
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
void init(int fdSem)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
|
|
|
if (sharedCount)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2008-10-11 04:42:01 +02:00
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
ftruncate(fdSem, sizeof(*this));
|
2008-10-11 04:42:01 +02:00
|
|
|
|
2008-10-21 06:25:49 +02:00
|
|
|
for (int i = 0; i < N_SETS; ++i)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
|
|
|
if (set[i].fileNum > 0)
|
|
|
|
{
|
|
|
|
// may be some old data about really active semaphore sets?
|
|
|
|
if (version == CURRENT_VERSION)
|
|
|
|
{
|
2009-06-02 08:27:23 +02:00
|
|
|
const int semId = semget(set[i].semKey, SEM_PER_SET, 0);
|
2008-10-10 17:58:05 +02:00
|
|
|
if (semId > 0)
|
|
|
|
{
|
|
|
|
semctl(semId, 0, IPC_RMID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
set[i].fileNum = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < N_FILES; ++i)
|
|
|
|
{
|
|
|
|
filesTable[i].name[0] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
version = CURRENT_VERSION;
|
|
|
|
lastSet = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool get(int fileNum, Sys5Semaphore* sem)
|
|
|
|
{
|
|
|
|
// try to locate existing set
|
|
|
|
int n;
|
2008-12-02 08:09:49 +01:00
|
|
|
for (n = 0; n < lastSet; ++n)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2008-10-16 10:52:33 +02:00
|
|
|
const int semNum = set[n].get(fileNum);
|
2008-10-10 17:58:05 +02:00
|
|
|
if (semNum >= 0)
|
|
|
|
{
|
|
|
|
sem->semSet = n;
|
|
|
|
sem->semNum = semNum;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// create new set
|
2008-12-02 08:09:49 +01:00
|
|
|
for (n = 0; n < lastSet; ++n)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
|
|
|
if (set[n].fileNum <= 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-10-11 04:42:01 +02:00
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
if (n >= N_SETS)
|
|
|
|
{
|
2011-10-13 13:31:15 +02:00
|
|
|
fb_assert(false); // Not supposed to overflow
|
2008-10-10 17:58:05 +02:00
|
|
|
return false;
|
|
|
|
}
|
2008-10-11 04:42:01 +02:00
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
if (n >= lastSet)
|
|
|
|
{
|
|
|
|
lastSet = n + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
set[n].semKey = ftok(filesTable[fileNum - 1].name, n);
|
|
|
|
sem->semSet = n;
|
|
|
|
sem->semNum = set[n].create(fileNum);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void put(Sys5Semaphore* sem)
|
|
|
|
{
|
|
|
|
fb_assert(sem->semSet >= 0 && sem->semSet < N_SETS);
|
|
|
|
|
|
|
|
set[sem->semSet].put(sem->semNum);
|
|
|
|
}
|
|
|
|
|
2008-10-16 10:52:33 +02:00
|
|
|
int findFileByName(const PathName& name) const
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
|
|
|
// Get a file ID in filesTable.
|
|
|
|
for (int fileId = 0; fileId < N_FILES; ++fileId)
|
|
|
|
{
|
|
|
|
if (name == filesTable[fileId].name)
|
|
|
|
{
|
|
|
|
return fileId + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// not found
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int addFileByName(const PathName& name)
|
|
|
|
{
|
|
|
|
int id = findFileByName(name);
|
|
|
|
if (id > 0)
|
|
|
|
{
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get a file ID in filesTable.
|
|
|
|
for (int fileId = 0; fileId < SemTable::N_FILES; ++fileId)
|
|
|
|
{
|
|
|
|
if (filesTable[fileId].name[0] == 0)
|
|
|
|
{
|
|
|
|
name.copyTo(filesTable[fileId].name, sizeof(filesTable[fileId].name));
|
|
|
|
return fileId + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// not found
|
|
|
|
fb_assert(false);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2008-10-11 04:42:01 +02:00
|
|
|
SemTable* semTable = NULL;
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
int idCache[SemTable::N_SETS];
|
|
|
|
GlobalPtr<Mutex> idCacheMutex;
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
void initCache()
|
|
|
|
{
|
|
|
|
MutexLockGuard guard(idCacheMutex);
|
|
|
|
memset(idCache, 0xff, sizeof idCache);
|
|
|
|
}
|
2009-01-03 10:14:29 +01:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
void SemTable::cleanup(int fNum, bool release)
|
|
|
|
{
|
|
|
|
fb_assert(fNum > 0 && fNum <= N_FILES);
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (release)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
filesTable[fNum - 1].name[0] = 0;
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
MutexLockGuard guard(idCacheMutex);
|
|
|
|
for (int n = 0; n < lastSet; ++n)
|
2011-10-13 13:31:15 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
if (set[n].fileNum == fNum)
|
2011-10-13 13:31:15 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
if (release)
|
|
|
|
{
|
|
|
|
Sys5Semaphore sem;
|
|
|
|
sem.semSet = n;
|
|
|
|
int id = sem.getId();
|
|
|
|
if (id >= 0)
|
|
|
|
{
|
|
|
|
semctl(id, 0, IPC_RMID);
|
|
|
|
}
|
|
|
|
set[n].fileNum = -1;
|
|
|
|
}
|
|
|
|
idCache[n] = -1;
|
2011-10-13 13:31:15 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
}
|
|
|
|
}
|
2011-10-27 03:04:14 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
// Left from DEB_EVNT code, keep for a while 'as is'. To be cleaned up later!!!
|
|
|
|
void initStart(const event_t* event) {}
|
|
|
|
void initStop(const event_t* event, int code) {}
|
|
|
|
void finiStart(const event_t* event) {}
|
|
|
|
void finiStop(const event_t* event) {}
|
2011-10-27 03:04:14 +02:00
|
|
|
|
2012-11-02 17:27:12 +01:00
|
|
|
} // anonymous namespace
|
2011-10-13 13:31:15 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
bool SharedMemoryBase::getSem5(Sys5Semaphore* sem)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Lock init file.
|
|
|
|
FileLockHolder lock(initFile);
|
2011-10-27 03:04:14 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (!semTable->get(fileNum, sem))
|
2011-10-13 13:31:15 +02:00
|
|
|
{
|
|
|
|
gds__log("semTable->get() failed");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2012-11-05 02:14:04 +01:00
|
|
|
catch (const Exception& ex)
|
2011-10-13 13:31:15 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
iscLogException("FileLock ctor failed in getSem5", ex);
|
2011-10-13 13:31:15 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
return false;
|
|
|
|
}
|
2011-10-13 13:31:15 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
void SharedMemoryBase::freeSem5(Sys5Semaphore* sem)
|
|
|
|
{
|
|
|
|
try
|
2011-10-13 13:31:15 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
// Lock init file.
|
|
|
|
FileLockHolder lock(initFile);
|
2011-10-13 13:31:15 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
semTable->put(sem);
|
2011-10-13 13:31:15 +02:00
|
|
|
}
|
2012-11-05 02:14:04 +01:00
|
|
|
catch (const Exception& ex)
|
2011-10-13 13:31:15 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
iscLogException("FileLock ctor failed in freeSem5", ex);
|
2011-10-13 13:31:15 +02:00
|
|
|
}
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int Sys5Semaphore::getId()
|
|
|
|
{
|
|
|
|
MutexLockGuard guard(idCacheMutex);
|
|
|
|
fb_assert(semSet >= 0 && semSet < SemTable::N_SETS);
|
2008-10-11 04:42:01 +02:00
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
int id = idCache[semSet];
|
2008-10-11 04:42:01 +02:00
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
if (id < 0)
|
|
|
|
{
|
2009-12-06 02:34:57 +01:00
|
|
|
Arg::StatusVector status;
|
2008-10-10 17:58:05 +02:00
|
|
|
id = create_semaphores(status, semTable->getKey(semSet), SemTable::SEM_PER_SET);
|
|
|
|
if (id >= 0)
|
|
|
|
{
|
|
|
|
idCache[semSet] = id;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-12-06 03:28:00 +01:00
|
|
|
iscLogStatus("create_semaphores failed:", status.value());
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
}
|
2008-10-11 04:42:01 +02:00
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
return id;
|
|
|
|
}
|
2008-10-11 04:42:01 +02:00
|
|
|
#endif // USE_SYS5SEMAPHORE
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2008-10-11 04:42:01 +02:00
|
|
|
#endif // UNIX
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#if defined(WIN_NT)
|
2008-10-21 08:17:03 +02:00
|
|
|
static bool make_object_name(TEXT*, size_t, const TEXT*, const TEXT*);
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
#ifdef USE_SYS5SEMAPHORE
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2011-10-13 13:31:15 +02:00
|
|
|
class TimerEntry : public Firebird::RefCntIface<Firebird::ITimer, FB_TIMER_VERSION>
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2011-10-13 13:31:15 +02:00
|
|
|
public:
|
|
|
|
TimerEntry(int id, USHORT num)
|
|
|
|
: semId(id), semNum(num)
|
|
|
|
{ }
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2011-10-13 13:31:15 +02:00
|
|
|
void FB_CARG handler()
|
|
|
|
{
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
union semun arg;
|
|
|
|
arg.val = 0;
|
|
|
|
int ret = semctl(semId, semNum, SETVAL, arg);
|
|
|
|
if (ret != -1)
|
|
|
|
break;
|
|
|
|
if (!SYSCALL_INTERRUPTED(errno))
|
|
|
|
{
|
|
|
|
gds__log("semctl() failed, errno %d\n", errno);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2011-10-13 13:31:15 +02:00
|
|
|
int FB_CARG release()
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2011-10-13 13:31:15 +02:00
|
|
|
if (--refCounter == 0)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2011-10-13 13:31:15 +02:00
|
|
|
delete this;
|
|
|
|
return 0;
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2011-10-13 13:31:15 +02:00
|
|
|
|
|
|
|
return 1;
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
2011-10-13 13:31:15 +02:00
|
|
|
bool operator== (Sys5Semaphore& sem)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2011-10-13 13:31:15 +02:00
|
|
|
return semId == sem.getId() && semNum == sem.semNum;
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2011-10-13 13:31:15 +02:00
|
|
|
|
|
|
|
private:
|
|
|
|
int semId;
|
|
|
|
USHORT semNum;
|
2008-10-10 17:58:05 +02:00
|
|
|
};
|
|
|
|
|
2011-10-13 13:31:15 +02:00
|
|
|
typedef HalfStaticArray<TimerEntry*, 64> TimerQueue;
|
2008-10-10 17:58:05 +02:00
|
|
|
GlobalPtr<TimerQueue> timerQueue;
|
2011-10-13 13:31:15 +02:00
|
|
|
GlobalPtr<Mutex> timerAccess;
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2011-10-13 13:31:15 +02:00
|
|
|
void addTimer(Sys5Semaphore* sem, int microSeconds)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2011-10-13 13:31:15 +02:00
|
|
|
TimerEntry* newTimer = new TimerEntry(sem->getId(), sem->semNum);
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2011-10-13 13:31:15 +02:00
|
|
|
MutexLockGuard guard(timerAccess);
|
|
|
|
timerQueue->push(newTimer);
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2011-10-13 13:31:15 +02:00
|
|
|
TimerInterfacePtr()->start(newTimer, microSeconds);
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void delTimer(Sys5Semaphore* sem)
|
|
|
|
{
|
2011-10-13 13:31:15 +02:00
|
|
|
bool found = false;
|
|
|
|
TimerEntry** t;
|
2008-10-10 17:58:05 +02:00
|
|
|
|
|
|
|
{
|
2011-10-13 13:31:15 +02:00
|
|
|
MutexLockGuard guard(timerAccess);
|
|
|
|
|
|
|
|
for (t = timerQueue->begin(); t < timerQueue->end(); ++t)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2011-10-13 13:31:15 +02:00
|
|
|
if (**t == *sem)
|
|
|
|
{
|
|
|
|
timerQueue->remove(t);
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-13 13:31:15 +02:00
|
|
|
if (found)
|
|
|
|
{
|
|
|
|
TimerInterfacePtr()->stop(*t);
|
|
|
|
}
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
2011-10-13 13:31:15 +02:00
|
|
|
SINT64 curTime()
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2011-10-13 13:31:15 +02:00
|
|
|
struct timeval cur_time;
|
|
|
|
struct timezone tzUnused;
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2011-10-13 13:31:15 +02:00
|
|
|
if (gettimeofday(&cur_time, &tzUnused) != 0)
|
|
|
|
{
|
|
|
|
system_call_failed::raise("gettimeofday");
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
2011-10-13 13:31:15 +02:00
|
|
|
SINT64 rc = ((SINT64) cur_time.tv_sec) * 1000000 + cur_time.tv_usec;
|
|
|
|
return rc;
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
2012-11-02 17:27:12 +01:00
|
|
|
} // anonymous namespace
|
2009-06-23 15:26:12 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#endif // USE_SYS5SEMAPHORE
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#ifdef USE_SHARED_FUTEX
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
int isPthreadError(int rc, const char* function)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
if (rc == 0)
|
|
|
|
return 0;
|
|
|
|
iscLogStatus("Pthread Error",
|
|
|
|
(Arg::Gds(isc_sys_request) << Arg::Str(function) << Arg::Unix(rc)).value());
|
|
|
|
return rc;
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#define PTHREAD_ERROR(x) if (isPthreadError((x), #x)) return FB_FAILURE
|
|
|
|
#define PTHREAD_ERRNO(x) { int tmpState = (x); if (isPthreadError(tmpState, #x)) return tmpState; }
|
|
|
|
#define LOG_PTHREAD_ERROR(x) isPthreadError((x), #x)
|
|
|
|
#define PTHREAD_ERR_STATUS(x, v) { int tmpState = (x); if (tmpState) { error(v, #x, tmpState); return false; } }
|
|
|
|
#define PTHREAD_ERR_RAISE(x) { int tmpState = (x); if (tmpState) { system_call_failed(#x, tmpState); } }
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#endif // USE_SHARED_FUTEX
|
2008-10-10 17:58:05 +02:00
|
|
|
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
int SharedMemoryBase::eventInit(event_t* event)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* I S C _ e v e n t _ i n i t ( S Y S V )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Prepare an event object for use.
|
|
|
|
*
|
|
|
|
**************************************/
|
2012-11-01 12:40:18 +01:00
|
|
|
|
|
|
|
#if defined(WIN_NT)
|
|
|
|
|
|
|
|
static AtomicCounter idCounter;
|
|
|
|
|
|
|
|
event->event_id = ++idCounter;
|
|
|
|
|
|
|
|
event->event_pid = process_id = getpid();
|
|
|
|
event->event_count = 0;
|
|
|
|
|
|
|
|
event->event_handle = ISC_make_signal(true, true, process_id, event->event_id);
|
|
|
|
|
|
|
|
return (event->event_handle) ? FB_SUCCESS : FB_FAILURE;
|
|
|
|
|
|
|
|
#elif defined(USE_SYS5SEMAPHORE)
|
|
|
|
|
2011-10-13 13:31:15 +02:00
|
|
|
initStart(event);
|
2008-10-10 17:58:05 +02:00
|
|
|
|
|
|
|
event->event_count = 0;
|
|
|
|
|
|
|
|
if (!getSem5(event))
|
|
|
|
{
|
|
|
|
IPC_TRACE(("ISC_event_init failed get sem %p\n", event));
|
2011-10-13 13:31:15 +02:00
|
|
|
initStop(event, 1);
|
2008-10-10 17:58:05 +02:00
|
|
|
return FB_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
IPC_TRACE(("ISC_event_init set=%d num=%d\n", event->semSet, event->semNum));
|
|
|
|
|
|
|
|
union semun arg;
|
|
|
|
arg.val = 0;
|
|
|
|
if (semctl(event->getId(), event->semNum, SETVAL, arg) < 0)
|
|
|
|
{
|
2011-10-13 13:31:15 +02:00
|
|
|
initStop(event, 2);
|
2009-12-06 03:28:00 +01:00
|
|
|
iscLogStatus("event_init()",
|
|
|
|
(Arg::Gds(isc_sys_request) << Arg::Str("semctl") << SYS_ERR(errno)).value());
|
2008-10-10 17:58:05 +02:00
|
|
|
return FB_FAILURE;
|
|
|
|
}
|
|
|
|
|
2011-10-13 13:31:15 +02:00
|
|
|
initStop(event, 0);
|
2008-10-10 17:58:05 +02:00
|
|
|
return FB_SUCCESS;
|
2012-11-01 12:40:18 +01:00
|
|
|
|
|
|
|
#else // pthread-based event
|
|
|
|
|
|
|
|
event->event_count = 0;
|
|
|
|
event->pid = getpid();
|
|
|
|
|
|
|
|
// Prepare an Inter-Process event block
|
|
|
|
pthread_mutexattr_t mattr;
|
|
|
|
pthread_condattr_t cattr;
|
|
|
|
|
|
|
|
PTHREAD_ERROR(pthread_mutexattr_init(&mattr));
|
|
|
|
PTHREAD_ERROR(pthread_condattr_init(&cattr));
|
|
|
|
#ifdef PTHREAD_PROCESS_SHARED
|
|
|
|
PTHREAD_ERROR(pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED));
|
|
|
|
PTHREAD_ERROR(pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED));
|
|
|
|
#else
|
|
|
|
#error Your system must support PTHREAD_PROCESS_SHARED to use firebird.
|
|
|
|
#endif
|
|
|
|
PTHREAD_ERROR(pthread_mutex_init(event->event_mutex, &mattr));
|
|
|
|
PTHREAD_ERROR(pthread_cond_init(event->event_cond, &cattr));
|
|
|
|
PTHREAD_ERROR(pthread_mutexattr_destroy(&mattr));
|
|
|
|
PTHREAD_ERROR(pthread_condattr_destroy(&cattr));
|
|
|
|
|
|
|
|
return FB_SUCCESS;
|
|
|
|
|
|
|
|
#endif // OS-dependent choice
|
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
void SharedMemoryBase::eventFini(event_t* event)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2012-11-01 12:40:18 +01:00
|
|
|
* I S C _ e v e n t _ f i n i
|
2008-10-10 17:58:05 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2012-11-01 12:40:18 +01:00
|
|
|
* Discard an event object.
|
2008-10-10 17:58:05 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#if defined(WIN_NT)
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (event->event_pid == process_id)
|
2009-06-23 15:26:12 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
CloseHandle((HANDLE) event->event_handle);
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#elif defined(USE_SYS5SEMAPHORE)
|
|
|
|
|
|
|
|
IPC_TRACE(("ISC_event_fini set=%d num=%d\n", event->semSet, event->semNum));
|
|
|
|
finiStart(event);
|
|
|
|
freeSem5(event);
|
|
|
|
finiStop(event);
|
|
|
|
|
|
|
|
#else // pthread-based event
|
|
|
|
|
|
|
|
if (event->pid == getpid())
|
|
|
|
{
|
|
|
|
LOG_PTHREAD_ERROR(pthread_mutex_destroy(event->event_mutex));
|
|
|
|
LOG_PTHREAD_ERROR(pthread_cond_destroy(event->event_cond));
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // OS-dependent choice
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SLONG SharedMemoryBase::eventClear(event_t* event)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* I S C _ e v e n t _ c l e a r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Clear an event preparatory to waiting on it. The order of
|
|
|
|
* battle for event synchronization is:
|
|
|
|
*
|
|
|
|
* 1. Clear event.
|
|
|
|
* 2. Test data structure for event already completed
|
|
|
|
* 3. Wait on event.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
#if defined(WIN_NT)
|
|
|
|
|
|
|
|
ResetEvent((HANDLE) event->event_handle);
|
|
|
|
|
|
|
|
return event->event_count + 1;
|
|
|
|
|
|
|
|
#elif defined(USE_SYS5SEMAPHORE)
|
|
|
|
|
|
|
|
union semun arg;
|
|
|
|
|
|
|
|
arg.val = 1;
|
|
|
|
if (semctl(event->getId(), event->semNum, SETVAL, arg) < 0)
|
|
|
|
{
|
|
|
|
iscLogStatus("event_clear()",
|
|
|
|
(Arg::Gds(isc_sys_request) << Arg::Str("semctl") << SYS_ERR(errno)).value());
|
|
|
|
}
|
|
|
|
|
|
|
|
return (event->event_count + 1);
|
|
|
|
|
|
|
|
#else // pthread-based event
|
|
|
|
|
|
|
|
LOG_PTHREAD_ERROR(pthread_mutex_lock(event->event_mutex));
|
|
|
|
const SLONG ret = event->event_count + 1;
|
|
|
|
LOG_PTHREAD_ERROR(pthread_mutex_unlock(event->event_mutex));
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
#endif // OS-dependent choice
|
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
int SharedMemoryBase::eventWait(event_t* event, const SLONG value, const SLONG micro_seconds)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2012-11-01 12:40:18 +01:00
|
|
|
* I S C _ e v e n t _ w a i t
|
2008-10-10 17:58:05 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2012-11-01 12:40:18 +01:00
|
|
|
* Wait on an event.
|
2008-10-10 17:58:05 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// If we're not blocked, the rest is a gross waste of time
|
2012-11-01 12:40:18 +01:00
|
|
|
|
|
|
|
if (!event_blocked(event, value)) {
|
2008-10-10 17:58:05 +02:00
|
|
|
return FB_SUCCESS;
|
2012-11-01 12:40:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(WIN_NT)
|
|
|
|
|
|
|
|
// Go into wait loop
|
|
|
|
|
|
|
|
const DWORD timeout = (micro_seconds > 0) ? micro_seconds / 1000 : INFINITE;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
2012-11-05 02:14:04 +01:00
|
|
|
if (!event_blocked(event, value))
|
2012-11-01 12:40:18 +01:00
|
|
|
return FB_SUCCESS;
|
|
|
|
|
|
|
|
const DWORD status = WaitForSingleObject(event->event_handle, timeout);
|
|
|
|
|
|
|
|
if (status != WAIT_OBJECT_0)
|
|
|
|
return FB_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(USE_SYS5SEMAPHORE)
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// Set up timers if a timeout period was specified.
|
2008-10-10 17:58:05 +02:00
|
|
|
SINT64 timeout = 0;
|
2008-10-21 06:25:49 +02:00
|
|
|
if (micro_seconds > 0)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2011-10-13 13:31:15 +02:00
|
|
|
timeout = curTime() + micro_seconds;
|
|
|
|
addTimer(event, micro_seconds);
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// Go into wait loop
|
2008-10-10 17:58:05 +02:00
|
|
|
|
|
|
|
int ret = FB_SUCCESS;
|
2008-10-21 06:25:49 +02:00
|
|
|
for (;;)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
|
|
|
if (!event_blocked(event, value))
|
|
|
|
break;
|
|
|
|
|
|
|
|
struct sembuf sb;
|
|
|
|
sb.sem_op = 0;
|
|
|
|
sb.sem_flg = 0;
|
|
|
|
sb.sem_num = event->semNum;
|
|
|
|
|
|
|
|
int rc = semop(event->getId(), &sb, 1);
|
|
|
|
if (rc == -1 && !SYSCALL_INTERRUPTED(errno))
|
|
|
|
{
|
|
|
|
gds__log("ISC_event_wait: semop failed with errno = %d", errno);
|
|
|
|
}
|
|
|
|
|
2008-10-21 06:25:49 +02:00
|
|
|
if (micro_seconds > 0)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
|
|
|
// distinguish between timeout and actually happened event
|
|
|
|
if (! event_blocked(event, value))
|
|
|
|
break;
|
|
|
|
|
|
|
|
// had timeout expired?
|
|
|
|
if (curTime() >= timeout) // really expired
|
|
|
|
{
|
|
|
|
ret = FB_FAILURE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// Cancel the handler. We only get here if a timeout was specified.
|
2008-10-21 06:25:49 +02:00
|
|
|
if (micro_seconds > 0)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
|
|
|
delTimer(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#else // pthread-based event
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// Set up timers if a timeout period was specified.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
struct timespec timer;
|
2009-06-23 15:26:12 +02:00
|
|
|
if (micro_seconds > 0)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
timer.tv_sec = time(NULL);
|
|
|
|
timer.tv_sec += micro_seconds / 1000000;
|
|
|
|
timer.tv_nsec = 1000 * (micro_seconds % 1000000);
|
|
|
|
}
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
int ret = FB_SUCCESS;
|
2008-10-10 17:58:05 +02:00
|
|
|
pthread_mutex_lock(event->event_mutex);
|
2009-06-23 15:26:12 +02:00
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (!event_blocked(event, value))
|
|
|
|
{
|
2002-11-14 09:33:08 +01:00
|
|
|
ret = FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// The Posix pthread_cond_wait & pthread_cond_timedwait calls
|
|
|
|
// atomically release the mutex and start a wait.
|
|
|
|
// The mutex is reacquired before the call returns.
|
2001-05-23 15:26:42 +02:00
|
|
|
if (micro_seconds > 0)
|
2003-10-30 10:49:40 +01:00
|
|
|
{
|
2008-10-10 17:58:05 +02:00
|
|
|
ret = pthread_cond_timedwait(event->event_cond, event->event_mutex, &timer);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-03-02 18:47:22 +01:00
|
|
|
#if (defined LINUX || defined DARWIN || defined HP11 || defined FREEBSD)
|
2003-10-30 10:49:40 +01:00
|
|
|
if (ret == ETIMEDOUT)
|
2001-05-23 15:26:42 +02:00
|
|
|
#else
|
2003-10-30 10:49:40 +01:00
|
|
|
if (ret == ETIME)
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
2003-10-30 10:49:40 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// The timer expired - see if the event occurred and return
|
|
|
|
// FB_SUCCESS or FB_FAILURE accordingly.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
if (event_blocked(event, value))
|
2003-10-30 10:49:40 +01:00
|
|
|
ret = FB_FAILURE;
|
|
|
|
else
|
|
|
|
ret = FB_SUCCESS;
|
|
|
|
break;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-10-30 10:49:40 +01:00
|
|
|
else
|
2008-10-10 17:58:05 +02:00
|
|
|
ret = pthread_cond_wait(event->event_cond, event->event_mutex);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-10-10 17:58:05 +02:00
|
|
|
pthread_mutex_unlock(event->event_mutex);
|
2001-05-23 15:26:42 +02:00
|
|
|
return ret;
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#endif // OS-dependent choice
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
|
|
|
|
int SharedMemoryBase::eventPost(event_t* event)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2012-11-01 12:40:18 +01:00
|
|
|
* I S C _ e v e n t _ p o s t
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2012-11-01 12:40:18 +01:00
|
|
|
* Post an event to wake somebody else up.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#if defined(WIN_NT)
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
++event->event_count;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (event->event_pid != process_id)
|
|
|
|
return ISC_kill(event->event_pid, event->event_id, event->event_handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
return SetEvent((HANDLE) event->event_handle) ? FB_SUCCESS : FB_FAILURE;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#elif defined(USE_SYS5SEMAPHORE)
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
union semun arg;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 10:07:24 +01:00
|
|
|
++event->event_count;
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
arg.val = 0;
|
|
|
|
int ret = semctl(event->getId(), event->semNum, SETVAL, arg);
|
|
|
|
if (ret != -1)
|
|
|
|
break;
|
|
|
|
if (!SYSCALL_INTERRUPTED(errno))
|
|
|
|
{
|
|
|
|
gds__log("ISC_event_post: semctl failed with errno = %d", errno);
|
|
|
|
return FB_FAILURE;
|
|
|
|
}
|
2008-01-16 10:07:24 +01:00
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
return FB_SUCCESS;
|
2008-01-16 10:07:24 +01:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#else // pthread-based event
|
2008-01-16 10:07:24 +01:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
PTHREAD_ERROR(pthread_mutex_lock(event->event_mutex));
|
|
|
|
++event->event_count;
|
|
|
|
const int ret = pthread_cond_broadcast(event->event_cond);
|
|
|
|
PTHREAD_ERROR(pthread_mutex_unlock(event->event_mutex));
|
|
|
|
if (ret)
|
2009-06-23 15:26:12 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
gds__log ("ISC_event_post: pthread_cond_broadcast failed with errno = %d", ret);
|
|
|
|
return FB_FAILURE;
|
|
|
|
}
|
2008-01-16 10:07:24 +01:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
return FB_SUCCESS;
|
|
|
|
|
|
|
|
#endif // OS-dependent choice
|
2008-01-16 10:07:24 +01:00
|
|
|
|
2012-11-02 17:27:12 +01:00
|
|
|
} // anonymous namespace
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef UNIX
|
2010-06-25 13:55:11 +02:00
|
|
|
ULONG ISC_exception_post(ULONG sig_num, const TEXT* err_msg)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2002-02-16 04:05:21 +01:00
|
|
|
* I S C _ e x c e p t i o n _ p o s t ( U N I X )
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2002-02-16 04:05:21 +01:00
|
|
|
* When we got a sync exception, fomulate the error code
|
2001-05-23 15:26:42 +02:00
|
|
|
* write it to the log file, and abort.
|
|
|
|
*
|
2004-03-09 01:17:07 +01:00
|
|
|
* 08-Mar-2004, Nickolay Samofatov.
|
|
|
|
* This function is dangerous and requires rewrite using signal-safe operations only.
|
|
|
|
* Main problem is that we call a lot of signal-unsafe functions from this signal handler,
|
2008-10-21 06:25:49 +02:00
|
|
|
* examples are gds__alloc, gds__log, etc... sprintf is safe on some BSD platforms,
|
2004-03-09 01:17:07 +01:00
|
|
|
* but not on Linux. This may result in lock-up during signal handling.
|
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
**************************************/
|
2004-02-20 07:43:27 +01:00
|
|
|
// If there's no err_msg, we asumed the switch() finds no case or we crash.
|
|
|
|
// Too much goodwill put on the caller. Weak programming style.
|
|
|
|
// Therefore, lifted this safety net from the NT version.
|
|
|
|
if (!err_msg)
|
|
|
|
{
|
|
|
|
err_msg = "";
|
|
|
|
}
|
|
|
|
|
2009-06-07 11:49:58 +02:00
|
|
|
TEXT* const log_msg = (TEXT *) gds__alloc(strlen(err_msg) + 256);
|
2004-03-09 01:17:07 +01:00
|
|
|
// NOMEM: crash!
|
2004-02-20 07:43:27 +01:00
|
|
|
log_msg[0] = '\0';
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-20 09:33:59 +01:00
|
|
|
switch (sig_num)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case SIGSEGV:
|
|
|
|
sprintf(log_msg, "%s Segmentation Fault.\n"
|
|
|
|
"\t\tThe code attempted to access memory\n"
|
|
|
|
"\t\twithout privilege to do so.\n"
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
case SIGBUS:
|
|
|
|
sprintf(log_msg, "%s Bus Error.\n"
|
|
|
|
"\t\tThe code caused a system bus error.\n"
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
case SIGILL:
|
|
|
|
|
|
|
|
sprintf(log_msg, "%s Illegal Instruction.\n"
|
|
|
|
"\t\tThe code attempted to perfrom an\n"
|
|
|
|
"\t\tillegal operation."
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGFPE:
|
|
|
|
sprintf(log_msg, "%s Floating Point Error.\n"
|
|
|
|
"\t\tThe code caused an arithmetic exception\n"
|
|
|
|
"\t\tor floating point exception."
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
sprintf(log_msg, "%s Unknown Exception.\n"
|
2006-01-18 11:43:13 +01:00
|
|
|
"\t\tException number %"ULONGFORMAT"."
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg, sig_num);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
if (err_msg)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
gds__log(log_msg);
|
|
|
|
gds__free(log_msg);
|
|
|
|
}
|
|
|
|
abort();
|
2010-06-25 13:55:11 +02:00
|
|
|
|
|
|
|
return 0; // compiler silencer
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-04-10 11:25:48 +02:00
|
|
|
#endif // UNIX
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef WIN_NT
|
2004-02-20 07:43:27 +01:00
|
|
|
ULONG ISC_exception_post(ULONG except_code, const TEXT* err_msg)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2002-02-16 04:05:21 +01:00
|
|
|
* I S C _ e x c e p t i o n _ p o s t ( W I N _ N T )
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2002-02-16 04:05:21 +01:00
|
|
|
* When we got a sync exception, fomulate the error code
|
2001-05-23 15:26:42 +02:00
|
|
|
* write it to the log file, and abort. Note: We can not
|
|
|
|
* actually call "abort" since in windows this will cause
|
|
|
|
* a dialog to appear stating the obvious! Since on NT we
|
|
|
|
* would not get a core file, there is actually no difference
|
2002-02-16 04:05:21 +01:00
|
|
|
* between abort() and exit(3).
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-20 07:43:27 +01:00
|
|
|
ULONG result = 0;
|
2002-11-16 16:54:21 +01:00
|
|
|
bool is_critical = true;
|
|
|
|
|
|
|
|
if (!err_msg)
|
|
|
|
{
|
|
|
|
err_msg = "";
|
|
|
|
}
|
|
|
|
|
2003-02-12 19:47:00 +01:00
|
|
|
TEXT* log_msg = (TEXT*) gds__alloc(strlen(err_msg) + 256);
|
2004-03-09 01:17:07 +01:00
|
|
|
// NOMEM: crash!
|
2003-02-12 19:47:00 +01:00
|
|
|
log_msg[0] = '\0';
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-20 09:33:59 +01:00
|
|
|
switch (except_code)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case EXCEPTION_ACCESS_VIOLATION:
|
|
|
|
sprintf(log_msg, "%s Access violation.\n"
|
|
|
|
"\t\tThe code attempted to access a virtual\n"
|
|
|
|
"\t\taddress without privilege to do so.\n"
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
|
|
|
sprintf(log_msg, "%s Datatype misalignment.\n"
|
|
|
|
"\t\tThe attempted to read or write a value\n"
|
|
|
|
"\t\tthat was not stored on a memory boundary.\n"
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
|
|
|
sprintf(log_msg, "%s Array bounds exceeded.\n"
|
|
|
|
"\t\tThe code attempted to access an array\n"
|
|
|
|
"\t\telement that is out of bounds.\n"
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
case EXCEPTION_FLT_DENORMAL_OPERAND:
|
|
|
|
sprintf(log_msg, "%s Float denormal operand.\n"
|
|
|
|
"\t\tOne of the floating-point operands is too\n"
|
|
|
|
"\t\tsmall to represent as a standard floating-point\n"
|
|
|
|
"\t\tvalue.\n"
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
|
|
|
sprintf(log_msg, "%s Floating-point divide by zero.\n"
|
|
|
|
"\t\tThe code attempted to divide a floating-point\n"
|
|
|
|
"\t\tvalue by a floating-point divisor of zero.\n"
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
case EXCEPTION_FLT_INEXACT_RESULT:
|
|
|
|
sprintf(log_msg, "%s Floating-point inexact result.\n"
|
|
|
|
"\t\tThe result of a floating-point operation cannot\n"
|
|
|
|
"\t\tbe represented exactly as a decimal fraction.\n"
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
case EXCEPTION_FLT_INVALID_OPERATION:
|
|
|
|
sprintf(log_msg, "%s Floating-point invalid operand.\n"
|
|
|
|
"\t\tAn indeterminant error occurred during a\n"
|
|
|
|
"\t\tfloating-point operation.\n"
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
case EXCEPTION_FLT_OVERFLOW:
|
|
|
|
sprintf(log_msg, "%s Floating-point overflow.\n"
|
|
|
|
"\t\tThe exponent of a floating-point operation\n"
|
|
|
|
"\t\tis greater than the magnitude allowed.\n"
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
case EXCEPTION_FLT_STACK_CHECK:
|
|
|
|
sprintf(log_msg, "%s Floating-point stack check.\n"
|
|
|
|
"\t\tThe stack overflowed or underflowed as the\n"
|
|
|
|
"result of a floating-point operation.\n"
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
case EXCEPTION_FLT_UNDERFLOW:
|
|
|
|
sprintf(log_msg, "%s Floating-point underflow.\n"
|
|
|
|
"\t\tThe exponent of a floating-point operation\n"
|
|
|
|
"\t\tis less than the magnitude allowed.\n"
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
|
|
|
sprintf(log_msg, "%s Integer divide by zero.\n"
|
|
|
|
"\t\tThe code attempted to divide an integer value\n"
|
|
|
|
"\t\tby an integer divisor of zero.\n"
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
case EXCEPTION_INT_OVERFLOW:
|
|
|
|
sprintf(log_msg, "%s Interger overflow.\n"
|
|
|
|
"\t\tThe result of an integer operation caused the\n"
|
|
|
|
"\t\tmost significant bit of the result to carry.\n"
|
2002-07-02 11:49:19 +02:00
|
|
|
"\tThis exception will cause the Firebird server\n"
|
2001-05-23 15:26:42 +02:00
|
|
|
"\tto terminate abnormally.", err_msg);
|
|
|
|
break;
|
|
|
|
case EXCEPTION_STACK_OVERFLOW:
|
2010-06-26 03:18:53 +02:00
|
|
|
status_exception::raise(Arg::Gds(isc_exception_stack_overflow));
|
2009-11-23 08:36:52 +01:00
|
|
|
// This will never be called, but to be safe it's here
|
2003-08-09 23:15:32 +02:00
|
|
|
result = (ULONG) EXCEPTION_CONTINUE_EXECUTION;
|
2002-11-16 16:54:21 +01:00
|
|
|
is_critical = false;
|
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case EXCEPTION_BREAKPOINT:
|
|
|
|
case EXCEPTION_SINGLE_STEP:
|
|
|
|
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
|
|
|
|
case EXCEPTION_INVALID_DISPOSITION:
|
|
|
|
case EXCEPTION_PRIV_INSTRUCTION:
|
|
|
|
case EXCEPTION_IN_PAGE_ERROR:
|
|
|
|
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
|
|
|
case EXCEPTION_GUARD_PAGE:
|
2009-11-23 08:36:52 +01:00
|
|
|
// Pass these exception on to someone else, probably the OS or the debugger,
|
|
|
|
// since there isn't a dam thing we can do with them
|
2002-11-16 16:54:21 +01:00
|
|
|
result = EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
is_critical = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2009-11-23 08:36:52 +01:00
|
|
|
case 0xE06D7363: // E == Exception. 0x6D7363 == "msc". Intel and Borland use the same code to be compatible
|
|
|
|
// If we've caught our own software exception,
|
|
|
|
// continue rewinding the stack to properly handle it
|
|
|
|
// and deliver an error information to the client side
|
2004-10-16 01:07:59 +02:00
|
|
|
result = EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
is_critical = false;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
sprintf (log_msg, "%s An exception occurred that does\n"
|
|
|
|
"\t\tnot have a description. Exception number %"XLONGFORMAT".\n"
|
|
|
|
"\tThis exception will cause the Firebird server\n"
|
|
|
|
"\tto terminate abnormally.", err_msg, except_code);
|
2008-10-21 06:25:49 +02:00
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2002-11-16 16:54:21 +01:00
|
|
|
|
2003-03-12 14:20:23 +01:00
|
|
|
if (is_critical)
|
|
|
|
{
|
|
|
|
gds__log(log_msg);
|
|
|
|
}
|
|
|
|
|
2002-11-16 16:54:21 +01:00
|
|
|
gds__free(log_msg);
|
|
|
|
|
|
|
|
if (is_critical)
|
|
|
|
{
|
2009-06-23 15:26:12 +02:00
|
|
|
if (Config::getBugcheckAbort())
|
|
|
|
{
|
2004-10-15 00:11:43 +02:00
|
|
|
// Pass exception to outer handler in case debugger is present to collect memory dump
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
}
|
2008-01-16 10:07:24 +01:00
|
|
|
|
|
|
|
// Silently exit so guardian or service manager can restart the server.
|
|
|
|
// If exception is getting out of the application Windows displays a message
|
|
|
|
// asking if you want to send report to Microsoft or attach debugger,
|
|
|
|
// application is not terminated until you press some button on resulting window.
|
2008-10-21 06:25:49 +02:00
|
|
|
// This happens even if you run application as non-interactive service on
|
2008-01-16 10:07:24 +01:00
|
|
|
// "server" OS like Windows Server 2003.
|
|
|
|
exit(3);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-01-16 10:07:24 +01:00
|
|
|
|
|
|
|
return result;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-04-10 11:25:48 +02:00
|
|
|
#endif // WIN_NT
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
void SharedMemoryBase::removeMapFile()
|
2009-04-08 13:00:58 +02:00
|
|
|
{
|
2010-06-05 02:48:06 +02:00
|
|
|
#ifndef WIN_NT
|
2012-11-01 12:40:18 +01:00
|
|
|
unlinkFile();
|
|
|
|
#else
|
|
|
|
sh_mem_unlink = true;
|
|
|
|
#endif // WIN_NT
|
|
|
|
}
|
|
|
|
|
|
|
|
void SharedMemoryBase::unlinkFile()
|
|
|
|
{
|
2009-04-08 13:00:58 +02:00
|
|
|
TEXT expanded_filename[MAXPATHLEN];
|
2010-06-25 13:55:11 +02:00
|
|
|
gds__prefix_lock(expanded_filename, sh_mem_name);
|
2009-04-11 21:41:01 +02:00
|
|
|
|
|
|
|
// We can't do much (specially in dtors) when it fails
|
|
|
|
// therefore do not check for errors - at least it's just /tmp.
|
|
|
|
unlink(expanded_filename);
|
2010-06-05 02:48:06 +02:00
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef UNIX
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
void SharedMemoryBase::internalUnmap()
|
|
|
|
{
|
|
|
|
#ifdef USE_SYS5SEMAPHORE
|
|
|
|
if (fileNum != -1 && mainLock.hasData())
|
|
|
|
{
|
|
|
|
Arg::StatusVector statusVector;
|
|
|
|
semTable->cleanup(fileNum, mainLock->setlock(statusVector, FileLock::FLM_TRY_EXCLUSIVE));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (sh_mem_header)
|
|
|
|
{
|
|
|
|
munmap(sh_mem_header, sh_mem_length_mapped);
|
|
|
|
sh_mem_header = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject* callback)
|
|
|
|
:
|
|
|
|
#ifdef HAVE_SHARED_MUTEX_SECTION
|
|
|
|
sh_mem_mutex(0),
|
|
|
|
#endif
|
|
|
|
sh_mem_length_mapped(0), sh_mem_header(NULL),
|
|
|
|
#ifdef USE_SYS5SEMAPHORE
|
|
|
|
fileNum(-1),
|
|
|
|
#endif
|
|
|
|
sh_mem_callback(callback)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2012-11-01 12:40:18 +01:00
|
|
|
* c t o r ( U N I X - m m a p )
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Try to map a given file. If we are the first (i.e. only)
|
|
|
|
* process to map the file, call a given initialization
|
|
|
|
* routine (if given) or punt (leaving the file unmapped).
|
|
|
|
*
|
|
|
|
**************************************/
|
2012-11-01 12:40:18 +01:00
|
|
|
Arg::StatusVector statusVector;
|
2009-01-28 13:27:18 +01:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
sh_mem_name[0] = '\0';
|
2010-06-25 13:55:11 +02:00
|
|
|
|
2009-01-28 13:27:18 +01:00
|
|
|
TEXT expanded_filename[MAXPATHLEN];
|
|
|
|
gds__prefix_lock(expanded_filename, filename);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// make the complete filename for the init file this file is to be used as a
|
|
|
|
// master lock to eliminate possible race conditions with just a single file
|
2012-11-01 12:40:18 +01:00
|
|
|
// locking. The race condition is caused as the conversion of an EXCLUSIVE
|
|
|
|
// lock to a SHARED lock is not atomic
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-28 13:27:18 +01:00
|
|
|
TEXT init_filename[MAXPATHLEN];
|
|
|
|
gds__prefix_lock(init_filename, INIT_FILE);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-28 13:27:18 +01:00
|
|
|
const bool trunc_flag = (length != 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// open the init lock file
|
2008-10-12 17:03:39 +02:00
|
|
|
MutexLockGuard guard(openFdInit);
|
2009-01-13 15:29:07 +01:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
initFile.reset(FB_NEW(*getDefaultMemoryPool()) FileLock(init_filename));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// get an exclusive lock on the INIT file with blocking
|
2012-11-01 12:40:18 +01:00
|
|
|
FileLockHolder initLock(initFile);
|
2008-10-10 17:58:05 +02:00
|
|
|
|
|
|
|
#ifdef USE_SYS5SEMAPHORE
|
2012-11-01 12:40:18 +01:00
|
|
|
class Sem5Init
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
public:
|
|
|
|
static void init(int fd)
|
2009-06-23 15:26:12 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
void* sTab = mmap(0, sizeof(SemTable), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
|
|
if ((U_IPTR) sTab == (U_IPTR) -1)
|
|
|
|
{
|
|
|
|
system_call_failed::raise("mmap");
|
|
|
|
}
|
|
|
|
|
|
|
|
semTable = (SemTable*) sTab;
|
|
|
|
initCache();
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
};
|
2008-10-10 17:58:05 +02:00
|
|
|
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
TEXT sem_filename[MAXPATHLEN];
|
|
|
|
gds__prefix_lock(sem_filename, SEM_FILE);
|
|
|
|
|
|
|
|
semFile.reset(FB_NEW(*getDefaultMemoryPool()) FileLock(sem_filename, Sem5Init::init));
|
|
|
|
|
|
|
|
fb_assert(semTable);
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (semFile->setlock(statusVector, FileLock::FLM_TRY_EXCLUSIVE))
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
semTable->init(semFile->getFd());
|
|
|
|
semFile->unlock();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
if (!semFile->setlock(statusVector, FileLock::FLM_SHARED))
|
2010-06-25 13:55:11 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
if (statusVector.hasData())
|
|
|
|
statusVector.raise();
|
|
|
|
else
|
|
|
|
(Arg::Gds(isc_random) << "Unknown error in setlock").raise();
|
2010-06-25 13:55:11 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// create lock in order to have file autoclosed on error
|
2012-11-01 12:40:18 +01:00
|
|
|
mainLock.reset(FB_NEW(*getDefaultMemoryPool()) FileLock(expanded_filename));
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
if (length == 0)
|
|
|
|
{
|
2009-11-23 08:36:52 +01:00
|
|
|
// Get and use the existing length of the shared segment
|
2004-02-20 07:43:27 +01:00
|
|
|
struct stat file_stat;
|
2012-11-01 12:40:18 +01:00
|
|
|
if (fstat(mainLock->getFd(), &file_stat) == -1)
|
2009-06-23 15:26:12 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("fstat");
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
length = file_stat.st_size;
|
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
if (length == 0)
|
|
|
|
{
|
|
|
|
// keep old text of message here - will be assigned a bit later
|
2012-11-01 12:40:18 +01:00
|
|
|
(Arg::Gds(isc_random) << "shmem_data->sh_mem_length_mapped is 0").raise();
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// map file to memory
|
2012-11-01 12:40:18 +01:00
|
|
|
void* const address = mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, mainLock->getFd(), 0);
|
2009-06-23 15:26:12 +02:00
|
|
|
if ((U_IPTR) address == (U_IPTR) -1)
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("mmap", errno);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
// this class is needed to cleanup mapping in case of error
|
|
|
|
class AutoUnmap
|
2008-06-22 19:31:12 +02:00
|
|
|
{
|
2008-10-10 17:58:05 +02:00
|
|
|
public:
|
2012-11-01 12:40:18 +01:00
|
|
|
explicit AutoUnmap(SharedMemoryBase* sm) : sharedMemory(sm)
|
|
|
|
{ }
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
void success()
|
2008-10-16 10:52:33 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
sharedMemory = NULL;
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
~AutoUnmap()
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
if (sharedMemory)
|
2008-10-10 17:58:05 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
sharedMemory->internalUnmap();
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
private:
|
2012-11-01 12:40:18 +01:00
|
|
|
SharedMemoryBase* sharedMemory;
|
2008-10-10 17:58:05 +02:00
|
|
|
};
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
AutoUnmap autoUnmap(this);
|
|
|
|
|
|
|
|
sh_mem_header = (MemoryHeader*) address;
|
2010-06-25 13:55:11 +02:00
|
|
|
sh_mem_length_mapped = length;
|
|
|
|
strcpy(sh_mem_name, filename);
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#if defined(HAVE_SHARED_MUTEX_SECTION) && defined(USE_MUTEX_MAP)
|
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
sh_mem_mutex = (mtx*) mapObject(statusVector, OFFSET(MemoryHeader*, mhb_mutex), sizeof(mtx));
|
|
|
|
if (!sh_mem_mutex)
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("mmap");
|
2010-06-25 13:55:11 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
#endif
|
2008-06-22 19:31:12 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#if defined(USE_SYS5SEMAPHORE)
|
|
|
|
#if !defined(USE_FILELOCKS)
|
|
|
|
|
|
|
|
sh_mem_mutex = &sh_mem_header->mhb_mutex;
|
|
|
|
|
|
|
|
#endif // USE_FILELOCKS
|
|
|
|
|
|
|
|
fileNum = semTable->addFileByName(expanded_filename);
|
|
|
|
|
|
|
|
#endif // USE_SYS5SEMAPHORE
|
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// Try to get an exclusive lock on the lock file. This will
|
|
|
|
// fail if somebody else has the exclusive or shared lock
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (mainLock->setlock(statusVector, FileLock::FLM_TRY_EXCLUSIVE))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
if (trunc_flag)
|
2012-11-01 12:40:18 +01:00
|
|
|
ftruncate(mainLock->getFd(), length);
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (callback->initialize(this, true))
|
2009-06-23 15:26:12 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
|
|
|
|
#ifdef HAVE_SHARED_MUTEX_SECTION
|
|
|
|
#ifdef USE_SYS5SEMAPHORE
|
|
|
|
|
|
|
|
if (!getSem5(sh_mem_mutex))
|
2010-06-25 13:55:11 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
callback->mutexBug(0, "getSem5()");
|
|
|
|
(Arg::Gds(isc_random) << "getSem5() failed").raise();
|
2010-06-25 13:55:11 +02:00
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
union semun arg;
|
|
|
|
arg.val = 1;
|
|
|
|
int state = semctl(sh_mem_mutex->getId(), sh_mem_mutex->semNum, SETVAL, arg);
|
|
|
|
if (state == -1)
|
2010-06-25 13:55:11 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
int err = errno;
|
|
|
|
callback->mutexBug(errno, "semctl");
|
|
|
|
system_call_failed::raise("semctl", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else // USE_SYS5SEMAPHORE
|
|
|
|
|
|
|
|
#if (defined(HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL) || defined(USE_ROBUST_MUTEX)) && defined(LINUX)
|
|
|
|
// glibc in linux does not conform to the posix standard. When there is no RT kernel,
|
|
|
|
// ENOTSUP is returned not by pthread_mutexattr_setprotocol(), but by
|
|
|
|
// pthread_mutex_init(). Use a hack to deal with this broken error reporting.
|
|
|
|
#define BUGGY_LINUX_MUTEX
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int state = 0;
|
|
|
|
|
|
|
|
#ifdef BUGGY_LINUX_MUTEX
|
|
|
|
static volatile bool staticBugFlag = false;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
bool bugFlag = staticBugFlag;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
pthread_mutexattr_t mattr;
|
|
|
|
|
|
|
|
PTHREAD_ERR_RAISE(pthread_mutexattr_init(&mattr));
|
|
|
|
#ifdef PTHREAD_PROCESS_SHARED
|
|
|
|
PTHREAD_ERR_RAISE(pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED));
|
|
|
|
#else
|
|
|
|
#error Your system must support PTHREAD_PROCESS_SHARED to use pthread shared futex in Firebird.
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL
|
|
|
|
#ifdef BUGGY_LINUX_MUTEX
|
|
|
|
if (!bugFlag)
|
|
|
|
{
|
|
|
|
#endif
|
|
|
|
int protocolRc = pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT);
|
|
|
|
if (protocolRc && (protocolRc != ENOTSUP))
|
|
|
|
{
|
|
|
|
iscLogStatus("Pthread Error", (Arg::Gds(isc_sys_request) <<
|
|
|
|
"pthread_mutexattr_setprotocol" << Arg::Unix(protocolRc)).value());
|
|
|
|
}
|
|
|
|
#ifdef BUGGY_LINUX_MUTEX
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef USE_ROBUST_MUTEX
|
|
|
|
#ifdef BUGGY_LINUX_MUTEX
|
|
|
|
if (!bugFlag)
|
|
|
|
{
|
|
|
|
#endif
|
|
|
|
LOG_PTHREAD_ERROR(pthread_mutexattr_setrobust_np(&mattr, PTHREAD_MUTEX_ROBUST_NP));
|
|
|
|
#ifdef BUGGY_LINUX_MUTEX
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
memset(sh_mem_mutex->mtx_mutex, 0, sizeof(*(sh_mem_mutex->mtx_mutex)));
|
|
|
|
//int state = LOG_PTHREAD_ERROR(pthread_mutex_init(sh_mem_mutex->mtx_mutex, &mattr));
|
|
|
|
state = pthread_mutex_init(sh_mem_mutex->mtx_mutex, &mattr);
|
|
|
|
|
|
|
|
if (state
|
|
|
|
#ifdef BUGGY_LINUX_MUTEX
|
|
|
|
&& (state != ENOTSUP || bugFlag)
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
{
|
|
|
|
iscLogStatus("Pthread Error", (Arg::Gds(isc_sys_request) <<
|
|
|
|
"pthread_mutex_init" << Arg::Unix(state)).value());
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_PTHREAD_ERROR(pthread_mutexattr_destroy(&mattr));
|
|
|
|
|
|
|
|
#ifdef BUGGY_LINUX_MUTEX
|
|
|
|
if (state == ENOTSUP && !bugFlag)
|
|
|
|
{
|
|
|
|
staticBugFlag = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
} while (false);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (state)
|
|
|
|
{
|
|
|
|
callback->mutexBug(state, "pthread_mutex_init");
|
|
|
|
system_call_failed::raise("pthread_mutex_init", state);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // USE_SYS5SEMAPHORE
|
|
|
|
#endif // HAVE_SHARED_MUTEX_SECTION
|
|
|
|
|
|
|
|
mainLock->unlock();
|
|
|
|
if (!mainLock->setlock(statusVector, FileLock::FLM_SHARED))
|
|
|
|
{
|
|
|
|
if (statusVector.hasData())
|
|
|
|
status_exception::raise(statusVector);
|
|
|
|
else
|
|
|
|
(Arg::Gds(isc_random) << "Unknown error in setlock(SHARED)").raise();
|
2010-06-25 13:55:11 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
2009-06-23 15:26:12 +02:00
|
|
|
else
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
if (callback->initialize(this, false))
|
2009-06-23 15:26:12 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
if (!mainLock->setlock(statusVector, FileLock::FLM_SHARED))
|
2010-06-25 13:55:11 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
if (statusVector.hasData())
|
|
|
|
status_exception::raise(statusVector);
|
|
|
|
else
|
|
|
|
(Arg::Gds(isc_random) << "Unknown error in setlock(SHARED)").raise();
|
2010-06-25 13:55:11 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#ifdef USE_FILELOCKS
|
|
|
|
sh_mem_fileMutex.reset(FB_NEW(*getDefaultMemoryPool()) FileLock(mainLock, 1));
|
|
|
|
#endif
|
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
#ifdef USE_SYS5SEMAPHORE
|
|
|
|
++sharedCount;
|
|
|
|
#endif
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
autoUnmap.success();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif // UNIX
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef WIN_NT
|
2012-11-01 12:40:18 +01:00
|
|
|
SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject* cb)
|
|
|
|
: sh_mem_mutex(0), sh_mem_length_mapped(0),
|
|
|
|
sh_mem_handle(0), sh_mem_object(0), sh_mem_interest(0), sh_mem_hdr_object(0),
|
|
|
|
sh_mem_hdr_address(0), sh_mem_header(NULL), sh_mem_callback(cb), sh_mem_unlink(false)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2012-11-01 12:40:18 +01:00
|
|
|
* c t o r ( W I N _ N T )
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Try to map a given file. If we are the first (i.e. only)
|
|
|
|
* process to map the file, call a given initialization
|
|
|
|
* routine (if given) or punt (leaving the file unmapped).
|
|
|
|
*
|
|
|
|
**************************************/
|
2012-11-01 12:40:18 +01:00
|
|
|
sh_mem_name[0] = '\0';
|
2010-06-25 13:55:11 +02:00
|
|
|
|
|
|
|
ISC_mutex_init(&sh_mem_winMutex, filename);
|
|
|
|
sh_mem_mutex = &sh_mem_winMutex;
|
|
|
|
|
2010-06-05 02:48:06 +02:00
|
|
|
HANDLE file_handle;
|
|
|
|
HANDLE event_handle = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
int retry_count = 0;
|
|
|
|
|
2009-01-28 13:27:18 +01:00
|
|
|
TEXT expanded_filename[MAXPATHLEN];
|
|
|
|
gds__prefix_lock(expanded_filename, filename);
|
|
|
|
|
|
|
|
const bool trunc_flag = (length != 0);
|
2010-06-05 02:48:06 +02:00
|
|
|
bool init_flag = false;
|
2008-06-20 05:52:59 +02:00
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// retry to attach to mmapped file if the process initializing dies during initialization.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
retry:
|
2010-06-05 02:48:06 +02:00
|
|
|
if (retry_count++ > 0)
|
2010-10-13 11:23:01 +02:00
|
|
|
THD_sleep(10);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-28 13:27:18 +01:00
|
|
|
file_handle = CreateFile(expanded_filename,
|
|
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
|
|
NULL,
|
|
|
|
OPEN_ALWAYS,
|
|
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
|
|
NULL);
|
2010-06-05 02:48:06 +02:00
|
|
|
DWORD err = GetLastError();
|
2009-06-23 15:26:12 +02:00
|
|
|
if (file_handle == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
2010-06-05 02:48:06 +02:00
|
|
|
if (err == ERROR_SHARING_VIOLATION)
|
|
|
|
goto retry;
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("CreateFile");
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-10-21 08:17:03 +02:00
|
|
|
// Check if file already exists
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-06-05 02:48:06 +02:00
|
|
|
const bool file_exists = (err == ERROR_ALREADY_EXISTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-10-21 08:17:03 +02:00
|
|
|
// Create an event that can be used to determine if someone has already
|
|
|
|
// initialized shared memory.
|
|
|
|
|
2009-02-03 12:02:00 +01:00
|
|
|
TEXT object_name[MAXPATHLEN];
|
2009-01-28 13:27:18 +01:00
|
|
|
if (!make_object_name(object_name, sizeof(object_name), filename, "_event"))
|
2008-10-21 08:17:03 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("make_object_name");
|
2008-10-21 08:17:03 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-06-05 02:48:06 +02:00
|
|
|
if (!init_flag)
|
2009-06-23 15:26:12 +02:00
|
|
|
{
|
2010-06-05 02:48:06 +02:00
|
|
|
event_handle = CreateEvent(ISC_get_security_desc(), TRUE, FALSE, object_name);
|
|
|
|
if (!event_handle)
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
DWORD err = GetLastError();
|
2010-06-05 02:48:06 +02:00
|
|
|
CloseHandle(file_handle);
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("CreateEvent", err);
|
2010-06-05 02:48:06 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-06-05 02:48:06 +02:00
|
|
|
init_flag = (GetLastError() != ERROR_ALREADY_EXISTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (init_flag && false) // What's the crap? AP 2012
|
2010-06-05 02:48:06 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
DWORD err = GetLastError();
|
2010-06-05 02:48:06 +02:00
|
|
|
CloseHandle(event_handle);
|
|
|
|
CloseHandle(file_handle);
|
2012-11-01 12:40:18 +01:00
|
|
|
Arg::Gds(isc_unavailable).raise();
|
2010-06-05 02:48:06 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
if (length == 0)
|
|
|
|
{
|
2009-11-23 08:36:52 +01:00
|
|
|
// Get and use the existing length of the shared segment
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
if ((length = GetFileSize(file_handle, NULL)) == -1)
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
DWORD err = GetLastError();
|
2001-05-23 15:26:42 +02:00
|
|
|
CloseHandle(event_handle);
|
|
|
|
CloseHandle(file_handle);
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("GetFileSize", err);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// All but the initializer will wait until the event is set. That
|
|
|
|
// is done after initialization is complete.
|
|
|
|
// Close the file and wait for the event to be set or time out.
|
|
|
|
// The file may be truncated.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
CloseHandle(file_handle);
|
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
if (!init_flag)
|
|
|
|
{
|
2009-11-23 08:36:52 +01:00
|
|
|
// Wait for 10 seconds. Then retry
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-02-26 12:03:09 +01:00
|
|
|
const DWORD ret_event = WaitForSingleObject(event_handle, 10000);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// If we timed out, just retry. It is possible that the
|
|
|
|
// process doing the initialization died before setting the event.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
if (ret_event == WAIT_TIMEOUT)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
CloseHandle(event_handle);
|
2009-06-23 15:26:12 +02:00
|
|
|
if (retry_count > 10)
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("WaitForSingleObject", 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
DWORD fdw_create;
|
2008-06-20 05:52:59 +02:00
|
|
|
if (init_flag && file_exists && trunc_flag)
|
2009-08-08 14:39:32 +02:00
|
|
|
fdw_create = TRUNCATE_EXISTING;
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
|
|
|
fdw_create = OPEN_ALWAYS;
|
|
|
|
|
2009-01-28 13:27:18 +01:00
|
|
|
file_handle = CreateFile(expanded_filename,
|
|
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
|
|
NULL,
|
|
|
|
fdw_create,
|
|
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
|
|
NULL);
|
2009-06-23 15:26:12 +02:00
|
|
|
if (file_handle == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
2009-08-08 14:41:45 +02:00
|
|
|
const DWORD err = GetLastError();
|
|
|
|
|
2010-06-05 02:48:06 +02:00
|
|
|
if ((err == ERROR_SHARING_VIOLATION) || (err == ERROR_FILE_NOT_FOUND && fdw_create == TRUNCATE_EXISTING))
|
|
|
|
{
|
|
|
|
if (!init_flag) {
|
|
|
|
CloseHandle(event_handle);
|
|
|
|
}
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
CloseHandle(event_handle);
|
|
|
|
|
2009-08-10 00:21:31 +02:00
|
|
|
if (err == ERROR_USER_MAPPED_FILE && init_flag && file_exists && trunc_flag)
|
2012-11-01 12:40:18 +01:00
|
|
|
Arg::Gds(isc_instance_conflict).raise();
|
2009-08-08 14:41:45 +02:00
|
|
|
else
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("CreateFile", err);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2011-02-02 12:51:24 +01:00
|
|
|
if (!init_flag)
|
|
|
|
{
|
|
|
|
if ((GetLastError() != ERROR_ALREADY_EXISTS) || SetFilePointer(file_handle, 0, NULL, FILE_END) == 0)
|
|
|
|
{
|
|
|
|
CloseHandle(event_handle);
|
|
|
|
CloseHandle(file_handle);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// Create a file mapping object that will be used to make remapping possible.
|
|
|
|
// The current length of real mapped file and its name are saved in it.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-28 13:27:18 +01:00
|
|
|
if (!make_object_name(object_name, sizeof(object_name), filename, "_mapping"))
|
2008-10-21 08:17:03 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
DWORD err = GetLastError();
|
2008-10-21 08:17:03 +02:00
|
|
|
CloseHandle(event_handle);
|
|
|
|
CloseHandle(file_handle);
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("make_object_name", err);
|
2008-10-21 08:17:03 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-28 13:27:18 +01:00
|
|
|
HANDLE header_obj = CreateFileMapping(INVALID_HANDLE_VALUE,
|
|
|
|
ISC_get_security_desc(),
|
|
|
|
PAGE_READWRITE,
|
|
|
|
0, 2 * sizeof(ULONG),
|
|
|
|
object_name);
|
2008-10-21 06:25:49 +02:00
|
|
|
if (header_obj == NULL)
|
2008-06-22 19:31:12 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
DWORD err = GetLastError();
|
2001-05-23 15:26:42 +02:00
|
|
|
CloseHandle(event_handle);
|
|
|
|
CloseHandle(file_handle);
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("CreateFileMapping", err);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-06-26 12:43:57 +02:00
|
|
|
|
|
|
|
if (!init_flag && GetLastError() != ERROR_ALREADY_EXISTS)
|
2008-06-25 03:46:50 +02:00
|
|
|
{
|
2008-06-26 12:43:57 +02:00
|
|
|
// We have made header_obj but we are not initializing.
|
|
|
|
// Previous owner is closed and clear all header_data.
|
|
|
|
// One need to retry.
|
|
|
|
CloseHandle(header_obj);
|
|
|
|
CloseHandle(event_handle);
|
|
|
|
CloseHandle(file_handle);
|
|
|
|
goto retry;
|
2008-06-25 03:46:50 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-28 13:27:18 +01:00
|
|
|
ULONG* const header_address = (ULONG*) MapViewOfFile(header_obj, FILE_MAP_WRITE, 0, 0, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
if (header_address == NULL)
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
DWORD err = GetLastError();
|
2001-05-23 15:26:42 +02:00
|
|
|
CloseHandle(header_obj);
|
|
|
|
CloseHandle(event_handle);
|
|
|
|
CloseHandle(file_handle);
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("MapViewOfFile", err);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// Set or get the true length of the file depending on whether or not we are the first user.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
if (init_flag)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
header_address[0] = length;
|
|
|
|
header_address[1] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
length = header_address[0];
|
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
// Create the real file mapping object.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-08-09 10:14:30 +02:00
|
|
|
TEXT mapping_name[64]; // enough for int32 as text
|
2009-08-08 14:39:32 +02:00
|
|
|
sprintf(mapping_name, "_mapping_%"ULONGFORMAT, header_address[1]);
|
|
|
|
|
|
|
|
if (!make_object_name(object_name, sizeof(object_name), filename, mapping_name))
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
DWORD err = GetLastError();
|
2009-08-08 14:39:32 +02:00
|
|
|
UnmapViewOfFile(header_address);
|
|
|
|
CloseHandle(header_obj);
|
|
|
|
CloseHandle(event_handle);
|
|
|
|
CloseHandle(file_handle);
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("make_object_name", err);
|
2009-08-08 14:39:32 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-28 13:27:18 +01:00
|
|
|
HANDLE file_obj = CreateFileMapping(file_handle,
|
|
|
|
ISC_get_security_desc(),
|
|
|
|
PAGE_READWRITE,
|
|
|
|
0, length,
|
2009-08-08 14:39:32 +02:00
|
|
|
object_name);
|
2009-06-23 15:26:12 +02:00
|
|
|
if (file_obj == NULL)
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
DWORD err = GetLastError();
|
2001-05-23 15:26:42 +02:00
|
|
|
UnmapViewOfFile(header_address);
|
|
|
|
CloseHandle(header_obj);
|
|
|
|
CloseHandle(event_handle);
|
|
|
|
CloseHandle(file_handle);
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("CreateFileMapping", err);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-10-21 08:17:03 +02:00
|
|
|
UCHAR* const address = (UCHAR*) MapViewOfFile(file_obj, FILE_MAP_WRITE, 0, 0, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
if (address == NULL)
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
DWORD err = GetLastError();
|
2001-05-23 15:26:42 +02:00
|
|
|
CloseHandle(file_obj);
|
|
|
|
UnmapViewOfFile(header_address);
|
|
|
|
CloseHandle(header_obj);
|
|
|
|
CloseHandle(event_handle);
|
|
|
|
CloseHandle(file_handle);
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("MapViewOfFile", err);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
sh_mem_header = (MemoryHeader*) address;
|
2010-06-25 13:55:11 +02:00
|
|
|
sh_mem_length_mapped = length;
|
2008-06-22 19:31:12 +02:00
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
if (!sh_mem_length_mapped)
|
2008-06-22 19:31:12 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
(Arg::Gds(isc_random) << "sh_mem_length_mapped is 0").raise();
|
2008-06-22 19:31:12 +02:00
|
|
|
}
|
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
sh_mem_handle = file_handle;
|
|
|
|
sh_mem_object = file_obj;
|
|
|
|
sh_mem_interest = event_handle;
|
|
|
|
sh_mem_hdr_object = header_obj;
|
|
|
|
sh_mem_hdr_address = header_address;
|
|
|
|
strcpy(sh_mem_name, filename);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
sh_mem_callback->initialize(this, init_flag);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
if (init_flag)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
FlushViewOfFile(address, 0);
|
2011-02-02 12:51:24 +01:00
|
|
|
|
|
|
|
DWORD err = 0;
|
2010-06-25 13:55:11 +02:00
|
|
|
if (SetFilePointer(sh_mem_handle, length, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ||
|
|
|
|
!SetEndOfFile(sh_mem_handle) ||
|
|
|
|
!FlushViewOfFile(address, 0))
|
2011-02-02 12:51:24 +01:00
|
|
|
{
|
|
|
|
err = GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
SetEvent(event_handle);
|
|
|
|
if (err)
|
2006-02-23 06:08:26 +01:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
system_call_failed::raise("SetFilePointer", err);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2002-08-26 14:14:55 +02:00
|
|
|
#ifdef HAVE_MMAP
|
2010-06-17 09:34:15 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
UCHAR* SharedMemoryBase::mapObject(Arg::StatusVector& statusVector, ULONG object_offset, ULONG object_length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2012-11-01 12:40:18 +01:00
|
|
|
* I S C _ m a p _ o b j e c t
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2012-11-01 12:40:18 +01:00
|
|
|
* Try to map an object given a file mapping.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2010-06-17 09:34:15 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
// Get system page size as this is the unit of mapping.
|
2009-04-10 18:53:01 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#ifdef SOLARIS
|
|
|
|
const long ps = sysconf(_SC_PAGESIZE);
|
|
|
|
if (ps == -1)
|
2009-04-29 10:33:51 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
error(statusVector, "sysconf", errno);
|
|
|
|
return NULL;
|
2009-04-29 10:33:51 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
#else
|
|
|
|
const int ps = getpagesize();
|
|
|
|
if (ps == -1)
|
2009-07-21 12:01:18 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
error(statusVector, "getpagesize", errno);
|
|
|
|
return NULL;
|
2009-07-21 12:01:18 +02:00
|
|
|
}
|
2009-11-26 17:03:48 +01:00
|
|
|
#endif
|
2012-11-01 12:40:18 +01:00
|
|
|
const ULONG page_size = (ULONG) ps;
|
2009-04-10 18:53:01 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
// Compute the start and end page-aligned offsets which contain the object being mapped.
|
2009-07-21 12:01:18 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
const ULONG start = (object_offset / page_size) * page_size;
|
|
|
|
const ULONG end = FB_ALIGN(object_offset + object_length, page_size);
|
|
|
|
const ULONG length = end - start;
|
2009-07-14 13:34:46 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
UCHAR* address = (UCHAR*) mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, mainLock->getFd(), start);
|
2009-07-14 13:34:46 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if ((U_IPTR) address == (U_IPTR) -1)
|
2009-07-14 13:34:46 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
error(statusVector, "mmap", errno);
|
|
|
|
return NULL;
|
2009-07-14 13:34:46 +02:00
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
// Return the virtual address of the mapped object.
|
2009-07-14 13:34:46 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
IPC_TRACE(("ISC_map_object in %p to %p %p\n", shmem_data->sh_mem_address, address, address + length));
|
2009-07-14 13:34:46 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
return address + (object_offset - start);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
void SharedMemoryBase::unmapObject(Arg::StatusVector& statusVector, UCHAR** object_pointer, ULONG object_length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2012-11-01 12:40:18 +01:00
|
|
|
* I S C _ u n m a p _ o b j e c t
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2012-11-01 12:40:18 +01:00
|
|
|
* Try to unmap an object given a file mapping.
|
|
|
|
* Zero the object pointer after a successful unmap.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2012-11-01 12:40:18 +01:00
|
|
|
// Get system page size as this is the unit of mapping.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#ifdef SOLARIS
|
|
|
|
const long ps = sysconf(_SC_PAGESIZE);
|
|
|
|
if (ps == -1)
|
2009-04-10 18:53:01 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
error(statusVector, "sysconf", errno);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
const int ps = getpagesize();
|
|
|
|
if (ps == -1)
|
|
|
|
{
|
|
|
|
error(statusVector, "getpagesize", errno);
|
|
|
|
return;
|
2009-04-10 18:53:01 +02:00
|
|
|
}
|
|
|
|
#endif
|
2012-11-01 12:40:18 +01:00
|
|
|
const size_t page_size = (ULONG) ps;
|
|
|
|
|
|
|
|
// Compute the start and end page-aligned addresses which contain the mapped object.
|
|
|
|
|
|
|
|
char* const start = (char*) ((U_IPTR) (*object_pointer) & ~(page_size - 1));
|
|
|
|
char* const end =
|
|
|
|
(char*) ((U_IPTR) ((*object_pointer + object_length) + (page_size - 1)) & ~(page_size - 1));
|
|
|
|
const size_t length = end - start;
|
|
|
|
|
|
|
|
if (munmap(start, length) == -1)
|
|
|
|
{
|
|
|
|
error(statusVector, "munmap", errno);
|
|
|
|
return; // false;
|
|
|
|
}
|
|
|
|
|
|
|
|
*object_pointer = NULL;
|
|
|
|
return; // true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
#endif // HAVE_MMAP
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#ifdef WIN_NT
|
|
|
|
|
|
|
|
UCHAR* SharedMemoryBase::mapObject(Arg::StatusVector& statusVector,
|
|
|
|
ULONG object_offset,
|
|
|
|
ULONG object_length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2012-11-01 12:40:18 +01:00
|
|
|
* I S C _ m a p _ o b j e c t
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2012-11-01 12:40:18 +01:00
|
|
|
* Try to map an object given a file mapping.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
SYSTEM_INFO sys_info;
|
|
|
|
GetSystemInfo(&sys_info);
|
|
|
|
const ULONG page_size = sys_info.dwAllocationGranularity;
|
|
|
|
|
|
|
|
// Compute the start and end page-aligned offsets which
|
|
|
|
// contain the object being mapped.
|
|
|
|
|
|
|
|
const ULONG start = (object_offset / page_size) * page_size;
|
|
|
|
const ULONG end = FB_ALIGN(object_offset + object_length, page_size);
|
|
|
|
const ULONG length = end - start;
|
|
|
|
const HANDLE handle = sh_mem_object;
|
|
|
|
|
|
|
|
UCHAR* address = (UCHAR*) MapViewOfFile(handle, FILE_MAP_WRITE, 0, start, length);
|
|
|
|
|
|
|
|
if (address == NULL)
|
|
|
|
{
|
|
|
|
error(statusVector, "MapViewOfFile", GetLastError());
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the virtual address of the mapped object.
|
|
|
|
|
|
|
|
return (address + (object_offset - start));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
void SharedMemoryBase::unmapObject(Arg::StatusVector& statusVector,
|
|
|
|
UCHAR** object_pointer, ULONG /*object_length*/)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2012-11-01 12:40:18 +01:00
|
|
|
* I S C _ u n m a p _ o b j e c t
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2012-11-01 12:40:18 +01:00
|
|
|
* Try to unmap an object given a file mapping.
|
|
|
|
* Zero the object pointer after a successful unmap.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2012-11-01 12:40:18 +01:00
|
|
|
SYSTEM_INFO sys_info;
|
|
|
|
GetSystemInfo(&sys_info);
|
|
|
|
const size_t page_size = sys_info.dwAllocationGranularity;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
// Compute the start and end page-aligned offsets which
|
|
|
|
// contain the object being mapped.
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
const UCHAR* start = (UCHAR*) ((U_IPTR) *object_pointer & ~(page_size - 1));
|
|
|
|
if (!UnmapViewOfFile(start))
|
|
|
|
{
|
|
|
|
error(statusVector, "UnmapViewOfFile", GetLastError());
|
|
|
|
return;
|
|
|
|
}
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
*object_pointer = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef WIN_NT
|
2007-02-27 10:59:24 +01:00
|
|
|
|
|
|
|
static const LPCSTR FAST_MUTEX_EVT_NAME = "%s_FM_EVT";
|
|
|
|
static const LPCSTR FAST_MUTEX_MAP_NAME = "%s_FM_MAP";
|
|
|
|
|
|
|
|
static const int DEFAULT_INTERLOCKED_SPIN_COUNT = 0;
|
|
|
|
static const int DEFAULT_INTERLOCKED_SPIN_COUNT_SMP = 200;
|
|
|
|
|
2011-02-02 13:11:05 +01:00
|
|
|
static SLONG pid = 0;
|
2007-04-21 05:27:36 +02:00
|
|
|
|
2007-04-17 23:34:22 +02:00
|
|
|
typedef WINBASEAPI BOOL (WINAPI *pfnSwitchToThread) ();
|
2007-04-21 05:27:36 +02:00
|
|
|
static inline BOOL switchToThread()
|
2007-04-17 23:34:22 +02:00
|
|
|
{
|
|
|
|
static pfnSwitchToThread fnSwitchToThread = NULL;
|
|
|
|
static bool bInit = false;
|
|
|
|
|
|
|
|
if (!bInit)
|
|
|
|
{
|
|
|
|
HMODULE hLib = GetModuleHandle("kernel32.dll");
|
2011-05-10 03:12:14 +02:00
|
|
|
if (hLib)
|
2007-04-17 23:34:22 +02:00
|
|
|
fnSwitchToThread = (pfnSwitchToThread) GetProcAddress(hLib, "SwitchToThread");
|
2011-05-10 03:12:14 +02:00
|
|
|
|
2007-04-17 23:34:22 +02:00
|
|
|
bInit = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL res = FALSE;
|
2011-05-10 03:12:14 +02:00
|
|
|
|
2008-10-21 06:25:49 +02:00
|
|
|
if (fnSwitchToThread)
|
2007-04-17 23:34:22 +02:00
|
|
|
{
|
|
|
|
const HANDLE hThread = GetCurrentThread();
|
|
|
|
SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
|
|
|
|
|
2009-04-11 21:41:01 +02:00
|
|
|
res = (*fnSwitchToThread)();
|
2007-04-17 23:34:22 +02:00
|
|
|
|
|
|
|
SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-05-14 07:17:53 +02:00
|
|
|
// MinGW has the wrong declaration for the operating system function.
|
|
|
|
#if defined __GNUC__
|
2007-04-18 13:02:41 +02:00
|
|
|
// Cast away volatile
|
2007-03-01 11:35:11 +01:00
|
|
|
#define FIX_TYPE(arg) const_cast<LPLONG>(arg)
|
|
|
|
#else
|
|
|
|
#define FIX_TYPE(arg) arg
|
|
|
|
#endif
|
|
|
|
|
2007-04-17 23:34:22 +02:00
|
|
|
|
|
|
|
static inline void lockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect, ULONG SpinCount)
|
2007-04-15 13:27:15 +02:00
|
|
|
{
|
2007-04-17 23:34:22 +02:00
|
|
|
while (InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 1) != 0)
|
|
|
|
{
|
2008-10-21 06:25:49 +02:00
|
|
|
ULONG j = SpinCount;
|
2007-04-17 23:34:22 +02:00
|
|
|
while (j != 0)
|
|
|
|
{
|
|
|
|
if (lpSect->lSpinLock == 0)
|
|
|
|
goto next;
|
|
|
|
j--;
|
|
|
|
}
|
2007-04-21 05:27:36 +02:00
|
|
|
switchToThread();
|
2007-04-17 23:34:22 +02:00
|
|
|
next:;
|
|
|
|
}
|
2007-04-15 13:27:15 +02:00
|
|
|
}
|
2007-04-17 23:34:22 +02:00
|
|
|
|
|
|
|
static inline bool tryLockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect)
|
|
|
|
{
|
|
|
|
return (InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 1) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void unlockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect)
|
|
|
|
{
|
|
|
|
InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static DWORD enterFastMutex(FAST_MUTEX* lpMutex, DWORD dwMilliseconds)
|
|
|
|
{
|
|
|
|
volatile FAST_MUTEX_SHARED_SECTION* lpSect = lpMutex->lpSharedInfo;
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
2009-06-23 15:26:12 +02:00
|
|
|
if (dwMilliseconds == 0)
|
|
|
|
{
|
2007-04-17 23:34:22 +02:00
|
|
|
if (!tryLockSharedSection(lpSect))
|
|
|
|
return WAIT_TIMEOUT;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lockSharedSection(lpSect, lpMutex->lSpinCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lpSect->lAvailable > 0)
|
|
|
|
{
|
|
|
|
lpSect->lAvailable--;
|
2011-02-02 13:11:05 +01:00
|
|
|
lpSect->lOwnerPID = pid;
|
2012-06-18 18:51:30 +02:00
|
|
|
#ifdef DEV_BUILD
|
|
|
|
lpSect->lThreadId = GetCurrentThreadId();
|
|
|
|
#endif
|
2007-04-17 23:34:22 +02:00
|
|
|
unlockSharedSection(lpSect);
|
|
|
|
return WAIT_OBJECT_0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dwMilliseconds == 0)
|
|
|
|
{
|
|
|
|
unlockSharedSection(lpSect);
|
|
|
|
return WAIT_TIMEOUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
InterlockedIncrement(FIX_TYPE(&lpSect->lThreadsWaiting));
|
|
|
|
unlockSharedSection(lpSect);
|
2008-10-21 06:25:49 +02:00
|
|
|
|
2007-04-17 23:34:22 +02:00
|
|
|
// TODO actual timeout can be of any length
|
2011-04-02 06:50:25 +02:00
|
|
|
const DWORD tm = (dwMilliseconds == INFINITE || dwMilliseconds > 5000) ? 5000 : dwMilliseconds;
|
2011-02-02 13:11:05 +01:00
|
|
|
const DWORD dwResult = WaitForSingleObject(lpMutex->hEvent, tm);
|
|
|
|
|
2007-04-17 23:34:22 +02:00
|
|
|
InterlockedDecrement(FIX_TYPE(&lpSect->lThreadsWaiting));
|
2008-10-21 06:25:49 +02:00
|
|
|
|
2011-02-02 13:11:05 +01:00
|
|
|
if (dwMilliseconds != INFINITE)
|
|
|
|
dwMilliseconds -= tm;
|
|
|
|
|
|
|
|
// if (dwResult != WAIT_OBJECT_0)
|
|
|
|
// return dwResult;
|
|
|
|
|
2011-04-25 14:56:27 +02:00
|
|
|
if (dwResult == WAIT_OBJECT_0)
|
|
|
|
continue;
|
2011-02-02 13:11:05 +01:00
|
|
|
if (dwResult == WAIT_ABANDONED)
|
2007-04-17 23:34:22 +02:00
|
|
|
return dwResult;
|
2011-02-02 13:11:05 +01:00
|
|
|
if (dwResult == WAIT_TIMEOUT && !dwMilliseconds)
|
|
|
|
return dwResult;
|
|
|
|
|
|
|
|
lockSharedSection(lpSect, lpMutex->lSpinCount);
|
|
|
|
if (lpSect->lOwnerPID > 0 && !lpSect->lAvailable)
|
|
|
|
{
|
|
|
|
if (!ISC_check_process_existence(lpSect->lOwnerPID))
|
|
|
|
{
|
2012-06-18 18:51:30 +02:00
|
|
|
#ifdef DEV_BUILD
|
2011-02-02 13:11:05 +01:00
|
|
|
gds__log("enterFastMutex: dead process detected, pid = %d", lpSect->lOwnerPID);
|
2012-06-18 18:51:30 +02:00
|
|
|
lpSect->lThreadId = 0;
|
2011-02-02 13:11:05 +01:00
|
|
|
#endif
|
|
|
|
lpSect->lOwnerPID = 0;
|
|
|
|
lpSect->lAvailable++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unlockSharedSection(lpSect);
|
2007-04-17 23:34:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool leaveFastMutex(FAST_MUTEX* lpMutex)
|
|
|
|
{
|
|
|
|
volatile FAST_MUTEX_SHARED_SECTION* lpSect = lpMutex->lpSharedInfo;
|
|
|
|
|
|
|
|
lockSharedSection(lpSect, lpMutex->lSpinCount);
|
|
|
|
if (lpSect->lAvailable >= 1)
|
|
|
|
{
|
|
|
|
unlockSharedSection(lpSect);
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
lpSect->lAvailable++;
|
|
|
|
if (lpSect->lThreadsWaiting)
|
|
|
|
SetEvent(lpMutex->hEvent);
|
2012-06-18 18:51:30 +02:00
|
|
|
fb_assert(lpSect->lOwnerPID == pid);
|
|
|
|
lpSect->lOwnerPID = -lpSect->lOwnerPID;
|
|
|
|
#ifdef DEV_BUILD
|
|
|
|
fb_assert(lpSect->lThreadId == GetCurrentThreadId());
|
|
|
|
lpSect->lThreadId = -lpSect->lThreadId;
|
|
|
|
#endif
|
2007-04-17 23:34:22 +02:00
|
|
|
unlockSharedSection(lpSect);
|
2007-04-15 13:27:15 +02:00
|
|
|
|
2007-04-17 23:34:22 +02:00
|
|
|
return true;
|
|
|
|
}
|
2007-03-01 11:35:11 +01:00
|
|
|
|
2007-02-27 10:59:24 +01:00
|
|
|
static inline void deleteFastMutex(FAST_MUTEX* lpMutex)
|
|
|
|
{
|
|
|
|
UnmapViewOfFile((FAST_MUTEX_SHARED_SECTION*)lpMutex->lpSharedInfo);
|
|
|
|
CloseHandle(lpMutex->hFileMap);
|
|
|
|
CloseHandle(lpMutex->hEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void setupMutex(FAST_MUTEX* lpMutex)
|
|
|
|
{
|
|
|
|
SYSTEM_INFO si;
|
|
|
|
GetSystemInfo(&si);
|
|
|
|
|
|
|
|
if (si.dwNumberOfProcessors > 1)
|
|
|
|
lpMutex->lSpinCount = DEFAULT_INTERLOCKED_SPIN_COUNT_SMP;
|
|
|
|
else
|
|
|
|
lpMutex->lSpinCount = DEFAULT_INTERLOCKED_SPIN_COUNT;
|
|
|
|
}
|
|
|
|
|
2008-10-21 06:25:49 +02:00
|
|
|
static bool initializeFastMutex(FAST_MUTEX* lpMutex, LPSECURITY_ATTRIBUTES lpAttributes,
|
2007-02-27 10:59:24 +01:00
|
|
|
BOOL bInitialState, LPCSTR lpName)
|
|
|
|
{
|
2011-02-02 13:11:05 +01:00
|
|
|
if (pid == 0)
|
|
|
|
pid = GetCurrentProcessId();
|
|
|
|
|
2007-02-27 10:59:24 +01:00
|
|
|
LPCSTR name = lpName;
|
|
|
|
|
|
|
|
if (strlen(lpName) + strlen(FAST_MUTEX_EVT_NAME) - 2 >= MAXPATHLEN)
|
|
|
|
{
|
|
|
|
// this is the same error which CreateEvent will return for long name
|
|
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
setupMutex(lpMutex);
|
|
|
|
|
2008-01-16 10:07:24 +01:00
|
|
|
char sz[MAXPATHLEN];
|
2007-02-27 10:59:24 +01:00
|
|
|
if (lpName)
|
|
|
|
{
|
|
|
|
sprintf(sz, FAST_MUTEX_EVT_NAME, lpName);
|
|
|
|
name = sz;
|
|
|
|
}
|
|
|
|
|
2011-04-25 14:56:27 +02:00
|
|
|
#ifdef DONT_USE_FAST_MUTEX
|
|
|
|
lpMutex->lpSharedInfo = NULL;
|
|
|
|
lpMutex->hEvent = CreateMutex(lpAttributes, bInitialState, name);
|
|
|
|
return (lpMutex->hEvent != NULL);
|
|
|
|
#else
|
2007-02-27 10:59:24 +01:00
|
|
|
lpMutex->hEvent = CreateEvent(lpAttributes, FALSE, FALSE, name);
|
2008-01-16 10:07:24 +01:00
|
|
|
DWORD dwLastError = GetLastError();
|
2007-02-27 10:59:24 +01:00
|
|
|
|
|
|
|
if (lpMutex->hEvent)
|
|
|
|
{
|
|
|
|
if (lpName)
|
|
|
|
sprintf(sz, FAST_MUTEX_MAP_NAME, lpName);
|
2007-11-06 13:03:57 +01:00
|
|
|
|
2007-02-27 10:59:24 +01:00
|
|
|
lpMutex->hFileMap = CreateFileMapping(
|
2008-10-21 06:25:49 +02:00
|
|
|
INVALID_HANDLE_VALUE,
|
|
|
|
lpAttributes,
|
|
|
|
PAGE_READWRITE,
|
|
|
|
0,
|
|
|
|
sizeof(FAST_MUTEX_SHARED_SECTION),
|
2007-02-27 10:59:24 +01:00
|
|
|
name);
|
2007-11-06 13:03:57 +01:00
|
|
|
|
2007-02-27 10:59:24 +01:00
|
|
|
dwLastError = GetLastError();
|
2007-11-06 13:03:57 +01:00
|
|
|
|
2007-02-27 10:59:24 +01:00
|
|
|
if (lpMutex->hFileMap)
|
|
|
|
{
|
2008-10-21 06:25:49 +02:00
|
|
|
lpMutex->lpSharedInfo = (FAST_MUTEX_SHARED_SECTION*)
|
2007-02-27 10:59:24 +01:00
|
|
|
MapViewOfFile(lpMutex->hFileMap, FILE_MAP_WRITE, 0, 0, 0);
|
2007-11-06 13:03:57 +01:00
|
|
|
|
2007-02-27 10:59:24 +01:00
|
|
|
if (lpMutex->lpSharedInfo)
|
|
|
|
{
|
|
|
|
if (dwLastError != ERROR_ALREADY_EXISTS)
|
|
|
|
{
|
2007-04-17 23:34:22 +02:00
|
|
|
lpMutex->lpSharedInfo->lSpinLock = 0;
|
2007-02-27 10:59:24 +01:00
|
|
|
lpMutex->lpSharedInfo->lThreadsWaiting = 0;
|
|
|
|
lpMutex->lpSharedInfo->lAvailable = bInitialState ? 0 : 1;
|
2011-02-02 13:11:05 +01:00
|
|
|
lpMutex->lpSharedInfo->lOwnerPID = bInitialState ? pid : 0;
|
2012-06-18 18:51:30 +02:00
|
|
|
#ifdef DEV_BUILD
|
|
|
|
lpMutex->lpSharedInfo->lThreadId = bInitialState ? GetCurrentThreadId() : 0;
|
|
|
|
#endif
|
2007-03-01 11:35:11 +01:00
|
|
|
InterlockedExchange(FIX_TYPE(&lpMutex->lpSharedInfo->fInitialized), 1);
|
2007-02-27 10:59:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-10-21 06:25:49 +02:00
|
|
|
while (!lpMutex->lpSharedInfo->fInitialized)
|
2007-04-21 05:27:36 +02:00
|
|
|
switchToThread();
|
2007-02-27 10:59:24 +01:00
|
|
|
}
|
2007-11-06 13:03:57 +01:00
|
|
|
|
2007-02-27 10:59:24 +01:00
|
|
|
SetLastError(dwLastError);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
CloseHandle(lpMutex->hFileMap);
|
|
|
|
}
|
|
|
|
CloseHandle(lpMutex->hEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
SetLastError(dwLastError);
|
|
|
|
return false;
|
2011-04-25 14:56:27 +02:00
|
|
|
#endif // DONT_USE_FAST_MUTEX
|
2007-02-27 10:59:24 +01:00
|
|
|
}
|
|
|
|
|
2009-01-02 07:36:12 +01:00
|
|
|
#ifdef NOT_USED_OR_REPLACED
|
2007-02-27 10:59:24 +01:00
|
|
|
static bool openFastMutex(FAST_MUTEX* lpMutex, DWORD DesiredAccess, LPCSTR lpName)
|
|
|
|
{
|
|
|
|
LPCSTR name = lpName;
|
|
|
|
|
|
|
|
if (strlen(lpName) + strlen(FAST_MUTEX_EVT_NAME) - 2 >= MAXPATHLEN)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
setupMutex(lpMutex);
|
|
|
|
|
2008-01-16 10:07:24 +01:00
|
|
|
char sz[MAXPATHLEN];
|
2007-02-27 10:59:24 +01:00
|
|
|
if (lpName)
|
|
|
|
{
|
|
|
|
sprintf(sz, FAST_MUTEX_EVT_NAME, lpName);
|
|
|
|
name = sz;
|
|
|
|
}
|
2008-10-21 06:25:49 +02:00
|
|
|
|
2007-02-27 10:59:24 +01:00
|
|
|
lpMutex->hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, name);
|
2008-10-21 06:25:49 +02:00
|
|
|
|
2008-01-16 10:07:24 +01:00
|
|
|
DWORD dwLastError = GetLastError();
|
2008-10-21 06:25:49 +02:00
|
|
|
|
2007-02-27 10:59:24 +01:00
|
|
|
if (lpMutex->hEvent)
|
|
|
|
{
|
|
|
|
if (lpName)
|
|
|
|
sprintf(sz, FAST_MUTEX_MAP_NAME, lpName);
|
2008-10-21 06:25:49 +02:00
|
|
|
|
2008-12-20 09:12:19 +01:00
|
|
|
lpMutex->hFileMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, name);
|
2008-10-21 06:25:49 +02:00
|
|
|
|
2007-02-27 10:59:24 +01:00
|
|
|
dwLastError = GetLastError();
|
2008-10-21 06:25:49 +02:00
|
|
|
|
2007-02-27 10:59:24 +01:00
|
|
|
if (lpMutex->hFileMap)
|
|
|
|
{
|
2008-10-21 06:25:49 +02:00
|
|
|
lpMutex->lpSharedInfo = (FAST_MUTEX_SHARED_SECTION*)
|
2007-02-27 10:59:24 +01:00
|
|
|
MapViewOfFile(lpMutex->hFileMap, FILE_MAP_WRITE, 0, 0, 0);
|
2008-10-21 06:25:49 +02:00
|
|
|
|
2007-02-27 10:59:24 +01:00
|
|
|
if (lpMutex->lpSharedInfo)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
CloseHandle(lpMutex->hFileMap);
|
|
|
|
}
|
|
|
|
CloseHandle(lpMutex->hEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
SetLastError(dwLastError);
|
|
|
|
return false;
|
|
|
|
}
|
2009-01-02 07:36:12 +01:00
|
|
|
#endif
|
2007-02-27 10:59:24 +01:00
|
|
|
|
|
|
|
static inline void setFastMutexSpinCount(FAST_MUTEX* lpMutex, ULONG SpinCount)
|
|
|
|
{
|
|
|
|
lpMutex->lSpinCount = SpinCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
int ISC_mutex_init(struct mtx* mutex, const TEXT* mutex_name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* I S C _ m u t e x _ i n i t ( W I N _ N T )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Initialize a mutex.
|
|
|
|
*
|
|
|
|
**************************************/
|
2002-11-16 16:54:21 +01:00
|
|
|
char name_buffer[MAXPATHLEN];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-10-21 08:17:03 +02:00
|
|
|
if (!make_object_name(name_buffer, sizeof(name_buffer), mutex_name, "_mutex"))
|
|
|
|
{
|
|
|
|
return FB_FAILURE;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-08-21 12:14:07 +02:00
|
|
|
if (initializeFastMutex(&mutex->mtx_fast, ISC_get_security_desc(), FALSE, name_buffer))
|
|
|
|
return FB_SUCCESS;
|
|
|
|
|
|
|
|
fb_assert(GetLastError() != 0);
|
|
|
|
return GetLastError();
|
2007-02-27 10:59:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-26 12:03:09 +01:00
|
|
|
void ISC_mutex_fini(struct mtx *mutex)
|
2007-02-27 10:59:24 +01:00
|
|
|
{
|
2008-10-10 17:58:05 +02:00
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m u t e x _ f i n i ( W I N _ N T )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Destroy a mutex.
|
|
|
|
*
|
|
|
|
**************************************/
|
2007-02-27 10:59:24 +01:00
|
|
|
if (mutex->mtx_fast.lpSharedInfo)
|
|
|
|
deleteFastMutex(&mutex->mtx_fast);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
int ISC_mutex_lock(struct mtx* mutex)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* I S C _ m u t e x _ l o c k ( W I N _ N T )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2009-04-11 07:47:13 +02:00
|
|
|
* Seize a mutex.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2007-02-27 10:59:24 +01:00
|
|
|
const DWORD status = (mutex->mtx_fast.lpSharedInfo) ?
|
|
|
|
enterFastMutex(&mutex->mtx_fast, INFINITE) :
|
2008-12-20 09:12:19 +01:00
|
|
|
WaitForSingleObject(mutex->mtx_fast.hEvent, INFINITE);
|
2007-02-27 10:59:24 +01:00
|
|
|
|
2008-10-16 10:52:33 +02:00
|
|
|
return (status == WAIT_OBJECT_0 || status == WAIT_ABANDONED) ? FB_SUCCESS : FB_FAILURE;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
int ISC_mutex_lock_cond(struct mtx* mutex)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* I S C _ m u t e x _ l o c k _ c o n d ( W I N _ N T )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2009-04-11 07:47:13 +02:00
|
|
|
* Conditionally seize a mutex.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2008-10-21 06:25:49 +02:00
|
|
|
const DWORD status = (mutex->mtx_fast.lpSharedInfo) ?
|
2008-12-20 09:12:19 +01:00
|
|
|
enterFastMutex(&mutex->mtx_fast, 0) : WaitForSingleObject(mutex->mtx_fast.hEvent, 0L);
|
2007-02-27 10:59:24 +01:00
|
|
|
|
2008-10-16 10:52:33 +02:00
|
|
|
return (status == WAIT_OBJECT_0 || status == WAIT_ABANDONED) ? FB_SUCCESS : FB_FAILURE;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
int ISC_mutex_unlock(struct mtx* mutex)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* I S C _ m u t e x _ u n l o c k ( W I N _ N T )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release a mutex.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2007-02-27 10:59:24 +01:00
|
|
|
if (mutex->mtx_fast.lpSharedInfo) {
|
|
|
|
return !leaveFastMutex(&mutex->mtx_fast);
|
|
|
|
}
|
2008-01-16 10:07:24 +01:00
|
|
|
|
|
|
|
return !ReleaseMutex(mutex->mtx_fast.hEvent);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2007-02-27 10:59:24 +01:00
|
|
|
|
|
|
|
|
|
|
|
void ISC_mutex_set_spin_count (struct mtx *mutex, ULONG spins)
|
|
|
|
{
|
2008-10-21 06:25:49 +02:00
|
|
|
if (mutex->mtx_fast.lpSharedInfo)
|
2007-02-27 10:59:24 +01:00
|
|
|
setFastMutexSpinCount(&mutex->mtx_fast, spins);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // WIN_NT
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef UNIX
|
2002-08-26 14:14:55 +02:00
|
|
|
#ifdef HAVE_MMAP
|
2001-05-23 15:26:42 +02:00
|
|
|
#define ISC_REMAP_FILE_DEFINED
|
2010-06-25 13:55:11 +02:00
|
|
|
bool SharedMemoryBase::remapFile(Arg::StatusVector& statusVector, ULONG new_length, bool flag)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* I S C _ r e m a p _ f i l e ( U N I X - m m a p )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Try to re-map a given file.
|
|
|
|
*
|
|
|
|
**************************************/
|
2010-06-25 13:55:11 +02:00
|
|
|
if (!new_length)
|
|
|
|
{
|
|
|
|
error(statusVector, "Zero new_length is requested", 0);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (flag)
|
2012-11-01 12:40:18 +01:00
|
|
|
ftruncate(mainLock->getFd(), new_length);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
MemoryHeader* const address = (MemoryHeader*)
|
2012-11-01 12:40:18 +01:00
|
|
|
mmap(0, new_length, PROT_READ | PROT_WRITE, MAP_SHARED, mainLock->getFd(), 0);
|
2003-08-10 02:39:51 +02:00
|
|
|
if ((U_IPTR) address == (U_IPTR) -1)
|
2010-06-25 13:55:11 +02:00
|
|
|
{
|
|
|
|
error(statusVector, "mmap() failed", errno);
|
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
munmap(sh_mem_header, sh_mem_length_mapped);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
IPC_TRACE(("ISC_remap_file %p to %p %d\n", sh_mem_header, address, new_length));
|
2008-10-10 17:58:05 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
sh_mem_header = (MemoryHeader*) address;
|
2010-06-25 13:55:11 +02:00
|
|
|
sh_mem_length_mapped = new_length;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#if defined(HAVE_SHARED_MUTEX_SECTION) && !defined(USE_MUTEX_MAP)
|
|
|
|
sh_mem_mutex = &sh_mem_header->mhb_mutex;
|
2010-06-25 13:55:11 +02:00
|
|
|
#endif
|
2008-06-22 19:31:12 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
return address;
|
|
|
|
}
|
2010-02-04 16:17:35 +01:00
|
|
|
#endif // HAVE_MMAP
|
|
|
|
#endif // UNIX
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef WIN_NT
|
|
|
|
#define ISC_REMAP_FILE_DEFINED
|
2010-06-26 03:18:53 +02:00
|
|
|
bool SharedMemoryBase::remapFile(Arg::StatusVector& statusVector,
|
2010-06-25 13:55:11 +02:00
|
|
|
ULONG new_length, bool flag)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* I S C _ r e m a p _ f i l e ( W I N _ N T )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Try to re-map a given file.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
if (flag)
|
2008-10-24 08:22:55 +02:00
|
|
|
{
|
2010-06-25 13:55:11 +02:00
|
|
|
if (SetFilePointer(sh_mem_handle, new_length, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ||
|
|
|
|
!SetEndOfFile(sh_mem_handle) ||
|
2012-11-01 12:40:18 +01:00
|
|
|
!FlushViewOfFile(sh_mem_header, 0))
|
2004-02-20 07:43:27 +01:00
|
|
|
{
|
2009-12-06 02:34:57 +01:00
|
|
|
error(statusVector, "SetFilePointer", GetLastError());
|
2001-05-23 15:26:42 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2008-10-24 08:22:55 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-23 08:36:52 +01:00
|
|
|
/* If the remap file exists, remap does not occur correctly.
|
|
|
|
* The file number is local to the process and when it is
|
|
|
|
* incremented and a new filename is created, that file may
|
|
|
|
* already exist. In that case, the file is not expanded.
|
|
|
|
* This will happen when the file is expanded more than once
|
|
|
|
* by concurrently running processes.
|
|
|
|
*
|
|
|
|
* The problem will be fixed by making sure that a new file name
|
|
|
|
* is generated with the mapped file is created.
|
|
|
|
*/
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-08-08 14:39:32 +02:00
|
|
|
HANDLE file_obj = NULL;
|
2002-11-16 16:54:21 +01:00
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
while (true)
|
|
|
|
{
|
2009-08-08 14:39:32 +02:00
|
|
|
TEXT mapping_name[64]; // enough for int32 as text
|
2010-06-25 13:55:11 +02:00
|
|
|
sprintf(mapping_name, "_mapping_%"ULONGFORMAT, sh_mem_hdr_address[1] + 1);
|
2009-08-08 14:39:32 +02:00
|
|
|
|
|
|
|
TEXT object_name[MAXPATHLEN];
|
2010-06-25 13:55:11 +02:00
|
|
|
if (!make_object_name(object_name, sizeof(object_name), sh_mem_name, mapping_name))
|
2009-08-08 14:39:32 +02:00
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
file_obj = CreateFileMapping(sh_mem_handle,
|
2009-01-28 13:27:18 +01:00
|
|
|
ISC_get_security_desc(),
|
|
|
|
PAGE_READWRITE,
|
|
|
|
0, new_length,
|
2009-08-08 14:39:32 +02:00
|
|
|
object_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-08-10 00:21:31 +02:00
|
|
|
if (!(GetLastError() == ERROR_ALREADY_EXISTS && flag))
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
CloseHandle(file_obj);
|
2009-08-08 14:39:32 +02:00
|
|
|
file_obj = NULL;
|
2010-06-25 13:55:11 +02:00
|
|
|
sh_mem_hdr_address[1]++;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
if (file_obj == NULL)
|
|
|
|
{
|
2009-12-06 02:34:57 +01:00
|
|
|
error(statusVector, "CreateFileMapping", GetLastError());
|
2001-05-23 15:26:42 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
MemoryHeader* const address = (MemoryHeader*) MapViewOfFile(file_obj, FILE_MAP_WRITE, 0, 0, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
if (address == NULL)
|
|
|
|
{
|
2009-12-06 02:34:57 +01:00
|
|
|
error(statusVector, "MapViewOfFile", GetLastError());
|
2001-05-23 15:26:42 +02:00
|
|
|
CloseHandle(file_obj);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
if (flag)
|
|
|
|
{
|
2010-06-25 13:55:11 +02:00
|
|
|
sh_mem_hdr_address[0] = new_length;
|
|
|
|
sh_mem_hdr_address[1]++;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
UnmapViewOfFile(sh_mem_header);
|
2010-06-25 13:55:11 +02:00
|
|
|
CloseHandle(sh_mem_object);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
sh_mem_header = (MemoryHeader*) address;
|
2010-06-25 13:55:11 +02:00
|
|
|
sh_mem_length_mapped = new_length;
|
|
|
|
sh_mem_object = file_obj;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
if (!sh_mem_length_mapped)
|
2012-11-01 12:40:18 +01:00
|
|
|
{
|
|
|
|
error(statusVector, "sh_mem_length_mapped is 0", 0);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-06-25 13:55:11 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
return (address);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
#ifndef ISC_REMAP_FILE_DEFINED
|
|
|
|
bool SharedMemoryBase::remapFile(Arg::StatusVector& statusVector, ULONG, bool)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2012-11-01 12:40:18 +01:00
|
|
|
* I S C _ r e m a p _ f i l e ( G E N E R I C )
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2012-11-01 12:40:18 +01:00
|
|
|
* Try to re-map a given file.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2012-11-01 12:40:18 +01:00
|
|
|
|
|
|
|
statusVector << Arg::Gds(isc_unavailable) <<
|
|
|
|
Arg::Gds(isc_random) << "SharedMemory::remapFile";
|
|
|
|
|
|
|
|
return NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
#ifdef USE_SYS5SEMAPHORE
|
|
|
|
|
2009-12-06 02:34:57 +01:00
|
|
|
static SLONG create_semaphores(Arg::StatusVector& statusVector, SLONG key, int semaphores)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2008-10-10 17:58:05 +02:00
|
|
|
* c r e a t e _ s e m a p h o r e s ( U N I X )
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2008-10-10 17:58:05 +02:00
|
|
|
* Create or find a block of semaphores.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2008-10-10 17:58:05 +02:00
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
// Try to open existing semaphore set
|
2009-06-04 15:16:34 +02:00
|
|
|
SLONG semid = semget(key, 0, 0);
|
2009-06-23 15:26:12 +02:00
|
|
|
if (semid == -1)
|
|
|
|
{
|
|
|
|
if (errno != ENOENT)
|
|
|
|
{
|
2009-12-06 02:34:57 +01:00
|
|
|
error(statusVector, "semget", errno);
|
2008-10-10 17:58:05 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2008-10-21 06:25:49 +02:00
|
|
|
}
|
2008-10-10 17:58:05 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
union semun arg;
|
2008-10-21 06:25:49 +02:00
|
|
|
semid_ds buf;
|
2008-10-10 17:58:05 +02:00
|
|
|
arg.buf = &buf;
|
|
|
|
// Get number of semaphores in opened set
|
2009-06-23 15:26:12 +02:00
|
|
|
if (semctl(semid, 0, IPC_STAT, arg) == -1)
|
|
|
|
{
|
2009-12-06 02:34:57 +01:00
|
|
|
error(statusVector, "semctl", errno);
|
2008-10-10 17:58:05 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if ((int) buf.sem_nsems >= semaphores)
|
|
|
|
return semid;
|
|
|
|
// Number of semaphores in existing set is too small. Discard it.
|
2009-06-23 15:26:12 +02:00
|
|
|
if (semctl(semid, 0, IPC_RMID) == -1)
|
|
|
|
{
|
2009-12-06 02:34:57 +01:00
|
|
|
error(statusVector, "semctl", errno);
|
2008-10-10 17:58:05 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2008-10-21 06:25:49 +02:00
|
|
|
|
2008-10-10 17:58:05 +02:00
|
|
|
// Try to create new semaphore set
|
|
|
|
semid = semget(key, semaphores, IPC_CREAT | IPC_EXCL | PRIV);
|
|
|
|
if (semid != -1)
|
|
|
|
{
|
|
|
|
// We want to limit access to semaphores, created here
|
|
|
|
// Reasonable access rights to them - exactly like security database has
|
2011-10-13 13:31:15 +02:00
|
|
|
const char* secDb = Config::getDefaultConfig()->getSecurityDatabase();
|
2008-10-10 17:58:05 +02:00
|
|
|
struct stat st;
|
|
|
|
if (stat(secDb, &st) == 0)
|
|
|
|
{
|
|
|
|
union semun arg;
|
|
|
|
semid_ds ds;
|
|
|
|
arg.buf = &ds;
|
|
|
|
ds.sem_perm.uid = geteuid() == 0 ? st.st_uid : geteuid();
|
|
|
|
ds.sem_perm.gid = st.st_gid;
|
|
|
|
ds.sem_perm.mode = st.st_mode;
|
|
|
|
semctl(semid, 0, IPC_SET, arg);
|
|
|
|
}
|
|
|
|
return semid;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-10-16 10:52:33 +02:00
|
|
|
|
2009-06-23 15:26:12 +02:00
|
|
|
if (errno != EEXIST)
|
|
|
|
{
|
2009-12-06 02:34:57 +01:00
|
|
|
error(statusVector, "semget", errno);
|
2008-10-16 10:52:33 +02:00
|
|
|
return -1;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
2008-10-10 17:58:05 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-02-04 16:17:35 +01:00
|
|
|
#endif // USE_SYS5SEMAPHORE
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef WIN_NT
|
2008-12-20 09:12:19 +01:00
|
|
|
static bool make_object_name(TEXT* buffer, size_t bufsize,
|
|
|
|
const TEXT* object_name,
|
|
|
|
const TEXT* object_type)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m a k e _ o b j e c t _ n a m e ( W I N _ N T )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Create an object name from a name and type.
|
|
|
|
* Also replace the file separator with "_".
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-20 07:43:27 +01:00
|
|
|
char hostname[64];
|
2008-10-21 08:17:03 +02:00
|
|
|
const int rc = snprintf(buffer, bufsize, object_name, ISC_get_host(hostname, sizeof(hostname)));
|
2009-09-03 13:17:46 +02:00
|
|
|
if (size_t(rc) == bufsize || rc <= 0)
|
2008-10-21 08:17:03 +02:00
|
|
|
{
|
|
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
char& limit = buffer[bufsize - 1];
|
|
|
|
limit = 0;
|
2008-10-21 06:25:49 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
char* p;
|
|
|
|
char c;
|
2001-05-23 15:26:42 +02:00
|
|
|
for (p = buffer; c = *p; p++)
|
2008-04-21 16:02:47 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (c == '/' || c == '\\' || c == ':')
|
|
|
|
*p = '_';
|
2008-04-21 16:02:47 +02:00
|
|
|
}
|
2008-10-21 08:17:03 +02:00
|
|
|
|
|
|
|
// We either append the full object type or produce failure.
|
|
|
|
if (p >= &limit || p + strlen(object_type) > &limit)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
strcpy(p, object_type);
|
2006-02-07 18:21:40 +01:00
|
|
|
|
|
|
|
// hvlad: windows file systems use case-insensitive file names
|
2008-10-21 06:25:49 +02:00
|
|
|
// while kernel objects such as events use case-sensitive names.
|
|
|
|
// Since we use root directory as part of kernel objects names
|
2007-02-19 14:05:27 +01:00
|
|
|
// we must use lower (or upper) register for object name to avoid
|
2006-02-07 18:21:40 +01:00
|
|
|
// misunderstanding between processes
|
|
|
|
strlwr(buffer);
|
2007-02-19 14:05:27 +01:00
|
|
|
|
2008-10-21 08:17:03 +02:00
|
|
|
// CVC: I'm not convinced that if this call has no space to put the prefix,
|
|
|
|
// we can ignore that fact, hence I changed that signature, too.
|
|
|
|
if (!fb_utils::prefix_kernel_object_name(buffer, bufsize))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-04-10 11:25:48 +02:00
|
|
|
#endif // WIN_NT
|
2010-06-25 13:55:11 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
void SharedMemoryBase::mutexLock()
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
#if defined(WIN_NT)
|
|
|
|
|
2012-11-03 11:55:16 +01:00
|
|
|
int state = ISC_mutex_lock(sh_mem_mutex);
|
2012-11-01 12:40:18 +01:00
|
|
|
|
|
|
|
#elif defined(USE_FILELOCKS)
|
|
|
|
|
|
|
|
int state = 0;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
localMutex.enter();
|
|
|
|
}
|
2012-11-05 02:14:04 +01:00
|
|
|
catch (const system_call_failed& fail)
|
2012-11-01 12:40:18 +01:00
|
|
|
{
|
|
|
|
state = fail.getErrorCode();
|
|
|
|
}
|
|
|
|
if (!state)
|
|
|
|
{
|
|
|
|
state = sh_mem_fileMutex->setlock(FileLock::FLM_EXCLUSIVE);
|
|
|
|
if (state)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
localMutex.leave();
|
|
|
|
}
|
2012-11-05 02:14:04 +01:00
|
|
|
catch (const Exception&)
|
2012-11-01 12:40:18 +01:00
|
|
|
{ }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(USE_SYS5SEMAPHORE)
|
|
|
|
|
|
|
|
struct sembuf sop;
|
|
|
|
sop.sem_num = sh_mem_mutex->semNum;
|
|
|
|
sop.sem_op = -1;
|
|
|
|
sop.sem_flg = SEM_UNDO;
|
|
|
|
|
|
|
|
int state;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
state = semop(sh_mem_mutex->getId(), &sop, 1);
|
|
|
|
if (state == 0)
|
|
|
|
break;
|
|
|
|
if (!SYSCALL_INTERRUPTED(errno))
|
|
|
|
{
|
|
|
|
state = errno;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#else // POSIX SHARED MUTEX
|
|
|
|
|
|
|
|
int state = pthread_mutex_lock(sh_mem_mutex->mtx_mutex);
|
|
|
|
#ifdef USE_ROBUST_MUTEX
|
|
|
|
if (state == EOWNERDEAD)
|
|
|
|
{
|
|
|
|
// We always perform check for dead process
|
|
|
|
// Therefore may safely mark mutex as recovered
|
|
|
|
LOG_PTHREAD_ERROR(pthread_mutex_consistent_np(sh_mem_mutex->mtx_mutex));
|
|
|
|
state = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif // os-dependent choice
|
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
if (state != 0)
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
sh_mem_callback->mutexBug(state, "mutexLock");
|
2010-06-25 13:55:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
bool SharedMemoryBase::mutexLockCond()
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
#if defined(WIN_NT)
|
|
|
|
|
2012-11-03 11:55:16 +01:00
|
|
|
return ISC_mutex_lock_cond(sh_mem_mutex) == 0;
|
2012-11-01 12:40:18 +01:00
|
|
|
|
|
|
|
#elif defined(USE_FILELOCKS)
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (!localMutex.tryEnter())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2012-11-05 02:14:04 +01:00
|
|
|
catch (const system_call_failed& fail)
|
2012-11-01 12:40:18 +01:00
|
|
|
{
|
|
|
|
int state = fail.getErrorCode();
|
|
|
|
sh_mem_callback->mutexBug(state, "mutexLockCond");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool rc = (sh_mem_fileMutex->setlock(FileLock::FLM_TRY_EXCLUSIVE) == 0);
|
|
|
|
if (!rc)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
localMutex.leave();
|
|
|
|
}
|
2012-11-05 02:14:04 +01:00
|
|
|
catch (const Exception&)
|
2012-11-01 12:40:18 +01:00
|
|
|
{ }
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
#elif defined(USE_SYS5SEMAPHORE)
|
|
|
|
|
|
|
|
struct sembuf sop;
|
|
|
|
sop.sem_num = sh_mem_mutex->semNum;
|
|
|
|
sop.sem_op = -1;
|
|
|
|
sop.sem_flg = SEM_UNDO | IPC_NOWAIT;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
int state = semop(sh_mem_mutex->getId(), &sop, 1);
|
|
|
|
if (state == 0)
|
|
|
|
return true;
|
|
|
|
if (!SYSCALL_INTERRUPTED(errno))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else // POSIX SHARED MUTEX
|
|
|
|
|
|
|
|
int state = pthread_mutex_trylock(sh_mem_mutex->mtx_mutex);
|
|
|
|
#ifdef USE_ROBUST_MUTEX
|
|
|
|
if (state == EOWNERDEAD)
|
|
|
|
{
|
|
|
|
// We always perform check for dead process
|
|
|
|
// Therefore may safely mark mutex as recovered
|
|
|
|
LOG_PTHREAD_ERROR(pthread_mutex_consistent_np(sh_mem_mutex->mtx_mutex));
|
|
|
|
state = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return state == 0;
|
|
|
|
|
|
|
|
#endif // os-dependent choice
|
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
void SharedMemoryBase::mutexUnlock()
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
#if defined(WIN_NT)
|
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
int state = ISC_mutex_unlock(sh_mem_mutex);
|
2012-11-01 12:40:18 +01:00
|
|
|
|
|
|
|
#elif defined(USE_FILELOCKS)
|
|
|
|
|
|
|
|
int state = 0;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
localMutex.leave();
|
|
|
|
}
|
2012-11-05 02:14:04 +01:00
|
|
|
catch (const system_call_failed& fail)
|
2012-11-01 12:40:18 +01:00
|
|
|
{
|
|
|
|
state = fail.getErrorCode();
|
|
|
|
}
|
|
|
|
if (!state)
|
|
|
|
{
|
|
|
|
sh_mem_fileMutex->unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(USE_SYS5SEMAPHORE)
|
|
|
|
|
|
|
|
struct sembuf sop;
|
|
|
|
sop.sem_num = sh_mem_mutex->semNum;
|
|
|
|
sop.sem_op = 1;
|
|
|
|
sop.sem_flg = SEM_UNDO;
|
|
|
|
|
|
|
|
int state;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
state = semop(sh_mem_mutex->getId(), &sop, 1);
|
|
|
|
if (state == 0)
|
|
|
|
break;
|
|
|
|
if (!SYSCALL_INTERRUPTED(errno))
|
|
|
|
{
|
|
|
|
state = errno;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#else // POSIX SHARED MUTEX
|
|
|
|
|
|
|
|
int state = pthread_mutex_unlock(sh_mem_mutex->mtx_mutex);
|
|
|
|
|
|
|
|
#endif // os-dependent choice
|
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
if (state != 0)
|
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
sh_mem_callback->mutexBug(state, "mutexUnlock");
|
2010-06-25 13:55:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
|
|
|
|
SharedMemoryBase::~SharedMemoryBase()
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* I S C _ u n m a p _ f i l e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Unmap a given file.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
#ifdef USE_SYS5SEMAPHORE
|
|
|
|
// freeSem5(sh_mem_mutex); no need - all set of semaphores will be gone
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Lock init file.
|
|
|
|
FileLockHolder initLock(initFile);
|
|
|
|
|
|
|
|
Arg::StatusVector statusVector; // ignored
|
|
|
|
mainLock->unlock();
|
|
|
|
semTable->cleanup(fileNum, mainLock->setlock(statusVector, FileLock::FLM_TRY_EXCLUSIVE));
|
|
|
|
}
|
2012-11-05 02:14:04 +01:00
|
|
|
catch (const Exception& ex)
|
2012-11-01 12:40:18 +01:00
|
|
|
{
|
|
|
|
iscLogException("ISC_unmap_file failed to lock init file", ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
--sharedCount;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(HAVE_SHARED_MUTEX_SECTION) && defined(USE_MUTEX_MAP)
|
|
|
|
Arg::StatusVector statusVector;
|
|
|
|
unmapObject(statusVector, (UCHAR**) &sh_mem_mutex, sizeof(mtx));
|
|
|
|
if (statusVector.hasData())
|
|
|
|
{
|
|
|
|
iscLogStatus("unmapObject failed", statusVector.value());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UNIX
|
|
|
|
internalUnmap();
|
|
|
|
#endif
|
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
#ifdef WIN_NT
|
2012-11-03 11:55:16 +01:00
|
|
|
Arg::StatusVector statusVector;
|
2012-11-01 12:40:18 +01:00
|
|
|
CloseHandle(sh_mem_interest);
|
|
|
|
if (!UnmapViewOfFile(sh_mem_header))
|
|
|
|
{
|
|
|
|
error(statusVector, "UnmapViewOfFile", GetLastError());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
CloseHandle(sh_mem_object);
|
|
|
|
|
|
|
|
CloseHandle(sh_mem_handle);
|
|
|
|
if (!UnmapViewOfFile(sh_mem_hdr_address))
|
|
|
|
{
|
|
|
|
error(statusVector, "UnmapViewOfFile", GetLastError());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
CloseHandle(sh_mem_hdr_object);
|
|
|
|
|
|
|
|
TEXT expanded_filename[MAXPATHLEN];
|
|
|
|
gds__prefix_lock(expanded_filename, sh_mem_name);
|
|
|
|
|
|
|
|
// Delete file only if it is not used by anyone else
|
|
|
|
HANDLE hFile = CreateFile(expanded_filename,
|
|
|
|
DELETE,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
OPEN_EXISTING,
|
|
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
|
|
CloseHandle(hFile);
|
|
|
|
|
|
|
|
ISC_mutex_fini(&sh_mem_winMutex);
|
|
|
|
sh_mem_mutex = NULL;
|
|
|
|
|
|
|
|
sh_mem_header = NULL;
|
|
|
|
|
|
|
|
if (sh_mem_unlink)
|
|
|
|
{
|
|
|
|
unlinkFile();
|
|
|
|
}
|
2010-06-25 13:55:11 +02:00
|
|
|
#endif
|
2012-11-01 12:40:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void SharedMemoryBase::logError(const char* text, const Arg::StatusVector& status)
|
2010-06-25 13:55:11 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
iscLogStatus(text, status.value());
|
2010-06-25 13:55:11 +02:00
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
|
2012-11-02 17:27:12 +01:00
|
|
|
static bool event_blocked(const event_t* event, const SLONG value)
|
2010-06-25 13:55:11 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* e v e n t _ b l o c k e d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* If a wait would block, return true.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
if (event->event_count >= value)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG_ISC_SYNC
|
|
|
|
printf("event_blocked: FALSE (eg something to report)\n");
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_ISC_SYNC
|
|
|
|
printf("event_blocked: TRUE (eg nothing happened yet)\n");
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
|
|
|
return true;
|
2010-06-25 13:55:11 +02:00
|
|
|
}
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
|
|
|
|
static void error(Arg::StatusVector& statusVector, const TEXT* string, ISC_STATUS status)
|
2010-06-25 13:55:11 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* e r r o r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* We've encountered an error, report it.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
statusVector << Arg::Gds(isc_sys_request) << Arg::Str(string) << SYS_ERR(status);
|
|
|
|
statusVector.makePermanent();
|
2010-06-25 13:55:11 +02:00
|
|
|
}
|