Logo Search packages:      
Sourcecode: firebird3.0 version File versions  Download package

isc_sync.cpp

/*
 *    PROGRAM:    JRD Access Method
 *    MODULE:           isc_sync.cpp
 *    DESCRIPTION:      General purpose but non-user routines.
 *
 * 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.15 Sean Leyne - Code Cleanup, removed obsolete "XENIX" port
 * 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "DELTA" port
 * 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "IMP" port
 *
 * 2002-02-23 Sean Leyne - Code Cleanup, removed old M88K and NCR3000 port
 *
 * 2002.10.27 Sean Leyne - Completed removal of obsolete "DG_X86" port
 * 2002.10.27 Sean Leyne - Completed removal of obsolete "M88K" port
 *
 * 2002.10.28 Sean Leyne - Completed removal of obsolete "DGUX" port
 * 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "DecOSF" port
 * 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "SGI" port
 *
 * 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
 *
 */

#include "firebird.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef SOLARIS
#include "../common/gdsassert.h"
#endif

#ifdef HPUX
#include <sys/pstat.h>
#endif

#include "../common/common.h"
#include "gen/iberror.h"
#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"
#include "../common/file_params.h"
#include "../common/gdsassert.h"
#include "../common/classes/fb_tls.h"
#include "../common/config/config.h"
#include "../common/utils_proto.h"
#include "../common/StatusArg.h"

#ifdef UNIX
#include <setjmp.h>
#endif

static int process_id;

#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif

// Unix specific stuff

#ifdef UNIX
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>

#ifdef HAVE_SYS_SIGNAL_H
#include <sys/signal.h>
#endif

#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#ifdef USE_SYS5SEMAPHORE
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>

#include "../common/classes/semaphore.h"
#endif

#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif

#include <sys/mman.h>

#define FTOK_KEY  15
#define PRIV            0666

//#ifndef SHMEM_DELTA
//#define SHMEM_DELTA   (1 << 22)
//#endif

//#ifndef SIGURG
//#define SIGURG        SIGINT
//#endif

#ifndef HAVE_SEMUN
union semun
{
      int val;
      struct semid_ds *buf;
      ushort *array;
};
#endif
#endif // UNIX

#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif

#ifndef HAVE_GETPAGESIZE
static size_t getpagesize()
{
      return PAGESIZE;
}
#endif

#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


// Windows NT

#ifdef WIN_NT

#include <process.h>
#include <windows.h>

#endif

using namespace Jrd;
using namespace Firebird;

static void       error(Arg::StatusVector&, const TEXT*, ISC_STATUS);
static bool       event_blocked(const event_t* event, const SLONG value);

#ifdef UNIX

#ifdef __cplusplus
extern "C" {
#endif
static void       longjmp_sig_handler(int);
#ifdef __cplusplus
}
#endif
static void       longjmp_sig_handler(int);
static GlobalPtr<Mutex> openFdInit;

namespace {

      // File lock holder
      class FileLock
      {
      public:
            enum LockLevel {LCK_NONE, LCK_SHARED, LCK_EXCL};
            enum DtorMode {CLOSED, OPENED, LOCKED};

            FileLock(Arg::StatusVector& aStatusVector, int pFd, DtorMode pMode = CLOSED)
                  : statusVector(aStatusVector), level(LCK_NONE), fd(pFd), dtorMode(pMode)
            { }

            ~FileLock()
            {
                  switch (dtorMode)
                  {
                  case LOCKED:
                        break;
                  case OPENED:
                        unlock();
                        break;
                  case CLOSED:
                        unlock();
                        close(fd);
                        break;
                  }
            }

      // unlocking can only put error into log file - we can't throw in dtors
            void unlock()
            {
                  if (level == LCK_NONE)
                  {
                        return;
                  }

#ifdef HAVE_FLOCK
                  if (flock(fd, LOCK_UN))
#else
                  struct flock lock;
                  lock.l_type = F_UNLCK;
                  lock.l_whence = 0;
                  lock.l_start = 0;
                  lock.l_len = 0;
                  if (fcntl(fd, F_SETLK, &lock) == -1)
#endif
                  {
                        Arg::StatusVector local;
                        error(local, NAME, errno);
                        iscLogStatus("Unlock error", local.value());
                  }
                  level = LCK_NONE;
            }

            // Call it to keep file locked & opened after dtor is called
            void setDtorMode(DtorMode mode) throw()
            {
                  dtorMode = mode;
            }

            // Call when using already locked file in ctor
            void setLevel(LockLevel l)
            {
                  level = l;
            }

            // All lock methods return true on success, false on error
            bool exclusive()
            {
                  return doLock(false, true);
            }

            bool tryExclusive()
            {
                  return doLock(false, false);
            }

            bool shared()
            {
                  return doLock(true, true);
            }

            bool tryShared()
            {
                  return doLock(true, false);
            }

      private:
            Arg::StatusVector& statusVector;
            LockLevel level;
            int fd;
            DtorMode dtorMode;
            static const char* NAME;

      private:
            bool doLock(bool shared, bool wait)
            {
                  const LockLevel newLevel = shared ? LCK_SHARED : LCK_EXCL;
                  if (newLevel == level)
                  {
                        return true;
                  }
                  if (level != LCK_NONE)
                  {
                        unlock();
                  }
#ifdef HAVE_FLOCK
                  if (flock(fd, (shared ? LOCK_SH : LOCK_EX) | (wait ? 0 : LOCK_NB)))
#else //use FCNTL
                  struct flock lock;
                  lock.l_type = shared ? F_RDLCK : F_WRLCK;
                  lock.l_whence = 0;
                  lock.l_start = 0;
                  lock.l_len = 0;
                  if (fcntl(fd, wait ? F_SETLKW : F_SETLK, &lock) == -1)
#endif
                  {
                        error(statusVector, NAME, errno);
                        return false;
                  }
                  level = newLevel;
                  return true;
            }
      };

      const char* FileLock::NAME =
#ifdef HAVE_FLOCK
            "flock";
#else //use FCNTL
            "fcntl";
#endif
}

#ifdef USE_SYS5SEMAPHORE

static SLONG      create_semaphores(Arg::StatusVector&, SLONG, int);

namespace {

      int fdSem = -1;
      int sharedCount = 0;
      int fd_init = -1;

      // this class is mapped into shared file
      class SemTable
      {
      public:
            const static int N_FILES = 8;
            const static int N_SETS = 256;
#if defined(DEV_BUILD) || defined(FREEBSD)
            const static int SEM_PER_SET = 4;   // force multiple sets allocation || work with default freebsd kernel
#else
            const static int SEM_PER_SET = 31;  // hard limit for some old systems, might set to 32
#endif
            const static unsigned char CURRENT_VERSION = 1;
            unsigned char version;

      private:
            int lastSet;

            struct
            {
                  char name[MAXPATHLEN];
            } filesTable[N_FILES];

            struct
            {
                  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];

      public:
            void cleanup(int fNum, bool release);

            key_t getKey(int semSet) const
            {
                  fb_assert(semSet >= 0 && semSet < lastSet);

                  return set[semSet].semKey;
            }

            void init()
            {
                  if (sharedCount)
                  {
                        return;
                  }

                  ftruncate(fdSem, sizeof(*this));

                  for (int i = 0; i < N_SETS; ++i)
                  {
                        if (set[i].fileNum > 0)
                        {
                              // may be some old data about really active semaphore sets?
                              if (version == CURRENT_VERSION)
                              {
                                    const int semId = semget(set[i].semKey, SEM_PER_SET, 0);
                                    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;
                  for (n = 0; n < lastSet; ++n)
                  {
                        const int semNum = set[n].get(fileNum);
                        if (semNum >= 0)
                        {
                              sem->semSet = n;
                              sem->semNum = semNum;
                              return true;
                        }
                  }

                  // create new set
                  for (n = 0; n < lastSet; ++n)
                  {
                        if (set[n].fileNum <= 0)
                        {
                              break;
                        }
                  }

                  if (n >= N_SETS)
                  {
                        return false;
                  }

                  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);
            }

            int findFileByName(const PathName& name) const
            {
                  // 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;
            }
      };

      SemTable* semTable = NULL;

      class SharedFile
      {
      public:
            SharedFile(const char* pName, void* address, int length)
                  : fileNum(semTable->addFileByName(pName)), from((UCHAR*) address), to(from + length)
            { }

            SharedFile() : fileNum(0), from(0), to(0) { }

            int getNum() const { return fileNum; }

            static SharedFile* locate(void* s)
            {
                  const int n = getByAddress((UCHAR*) s);
                  return n >= 0 ? &sharedFiles[n] : 0;
            }

            static void push(const SharedFile& sf)
            {
                  MutexLockGuard guard(mutex);
                  IPC_TRACE(("+add SF with %p %p\n", sf.from, sf.to));
                  sharedFiles.push(sf);
            }

            static void pop()
            {
                  MutexLockGuard guard(mutex);
                  SharedFile sf = sharedFiles.pop();
                  IPC_TRACE(("-pop SF with %p %p\n", sf.from, sf.to));
            }

            static void remove(void* s)
            {
                  MutexLockGuard guard(mutex);
                  int n = getByAddress((UCHAR*) s);
                  if (n >= 0)
                  {
                        IPC_TRACE(("-rem SF with %p %p\n", sharedFiles[n].from, sharedFiles[n].to));
                        sharedFiles.remove(n);
                  }
                  else {
                        IPC_TRACE(("-rem SF Failedp\n"));
                  }
            }

            static void remap(void* const f, void* const to, int newLength)
            {
                  MutexLockGuard guard(mutex);
                  UCHAR* const from = (UCHAR*) f;
                  for (unsigned int n = 0; n < sharedFiles.getCount(); ++n)
                  {
                        if (from == sharedFiles[n].from)
                        {
                              sharedFiles[n].from = (UCHAR*) to;
                              sharedFiles[n].to = sharedFiles[n].from + newLength;
                              return;
                        }
                  }
            }

            typedef Vector<SharedFile, SemTable::N_FILES> Storage;

      private:
            int fileNum;
            const UCHAR* from;
            const UCHAR* to;
            static Storage sharedFiles;
            static GlobalPtr<Mutex> mutex;

            static int getByAddress(UCHAR* const s)
            {
                  MutexLockGuard guard(mutex);
                  for (unsigned int n = 0; n < sharedFiles.getCount(); ++n)
                  {
                        if (s >= sharedFiles[n].from && s < sharedFiles[n].to)
                        {
                              return n;
                        }
                  }

                  return -1;
            }
      };

      SharedFile::Storage SharedFile::sharedFiles;
      GlobalPtr<Mutex> SharedFile::mutex;

      int idCache[SemTable::N_SETS];
      GlobalPtr<Mutex> idCacheMutex;

      void initCache()
      {
            MutexLockGuard guard(idCacheMutex);
            memset(idCache, 0xff, sizeof idCache);
      }

      void SemTable::cleanup(int fNum, bool release)
      {
            fb_assert(fNum > 0 && fNum <= N_FILES);

            if (release)
            {
                  filesTable[fNum - 1].name[0] = 0;
            }

            MutexLockGuard guard(idCacheMutex);
            for (int n = 0; n < lastSet; ++n)
            {
                  if (set[n].fileNum == fNum)
                  {
                        if (release)
                        {
                              Sys5Semaphore sem;
                              sem.semSet = n;
                              int id = sem.getId();
                              if (id >= 0)
                              {
                                    semctl(id, 0, IPC_RMID);
                              }
                        }
                        idCache[n] = -1;
                  }
            }
      }

      bool getSem5(Sys5Semaphore* sem)
      {
            Arg::StatusVector status;

            // Lock init file.
            FileLock initLock(status, fd_init, FileLock::OPENED);
            if (!initLock.exclusive())
                  return false;

            // Find out what file does it belong to.
            SharedFile* sf = SharedFile::locate(sem);
            if (!sf)
            {
                  return false;
            }

            return semTable->get(sf->getNum(), sem);
      }

      void freeSem5(Sys5Semaphore* sem)
      {
            Arg::StatusVector status;

            // Lock init file.
            FileLock initLock(status, fd_init, FileLock::OPENED);
            if (!initLock.exclusive())
            {
                  iscLogStatus("freeSem5 failed to lock init file", status.value());
                  return;
            }

            semTable->put(sem);
      }
}

int Sys5Semaphore::getId()
{
      MutexLockGuard guard(idCacheMutex);
      fb_assert(semSet >= 0 && semSet < SemTable::N_SETS);

      int id = idCache[semSet];

      if (id < 0)
      {
            Arg::StatusVector status;
            id = create_semaphores(status, semTable->getKey(semSet), SemTable::SEM_PER_SET);
            if (id >= 0)
            {
                  idCache[semSet] = id;
            }
            else
            {
                  iscLogStatus("create_semaphores failed:", status.value());
            }
      }

      return id;
}
#endif // USE_SYS5SEMAPHORE

#endif // UNIX

#if defined(WIN_NT)
static bool make_object_name(TEXT*, size_t, const TEXT*, const TEXT*);
#endif

#if defined FREEBSD || defined NETBSD || defined DARWIN || defined HPUX
#define sigset      signal
#endif


static bool event_blocked(const event_t* event, const SLONG value)
{
/**************************************
 *
 *    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;
}


#ifdef USE_POSIX_THREADS

#ifdef USE_SYS5SEMAPHORE

namespace {

GlobalPtr<Mutex> timerAccess;
GlobalPtr<Semaphore> timerWakeup, timerFini;

void stopTimers(void*);
bool stopThread = false;

struct TimerEntry
{
      SINT64 fireTime;
      int semId;
      USHORT semNum;

      static const SINT64& generate(const void* /*sender*/, const TimerEntry& item) { return item.fireTime; }
      static THREAD_ENTRY_DECLARE timeThread(THREAD_ENTRY_PARAM);

      static void init()
      {
            int rc = gds__thread_start(timeThread, 0, 0, 0, 0);
            if (rc != 0)
            {
                  fatal_exception::raiseFmt("Error starting timer thread");
            }
            gds__register_cleanup(stopTimers, 0);
      }

      static void cleanup()
      {
            stopThread = true;
            timerWakeup->release();
            timerFini->enter();
      }
};

typedef SortedArray<TimerEntry, InlineStorage<TimerEntry, 64>, SINT64, TimerEntry> TimerQueue;
GlobalPtr<TimerQueue> timerQueue;

InitMutex<TimerEntry> timerHolder;

SINT64 curTime()
{
      struct timeval cur_time;
      struct timezone tzUnused;

      if (gettimeofday(&cur_time, &tzUnused) != 0)
      {
            system_call_failed::raise("gettimeofday");
      }

      SINT64 timeout = ((SINT64) cur_time.tv_sec) * 1000000 + cur_time.tv_usec;
      return timeout;
}

SINT64 addTimer(Sys5Semaphore* sem, int microSeconds)
{
      timerHolder.init();

      TimerEntry newTimer;
      newTimer.fireTime = curTime() + microSeconds;
      newTimer.semId = sem->getId();
      newTimer.semNum = sem->semNum;

      MutexLockGuard guard(timerAccess);

      timerQueue->add(newTimer);
      timerWakeup->release();

      return newTimer.fireTime;
}

void delTimer(Sys5Semaphore* sem)
{
      const int id = sem->getId();

      MutexLockGuard guard(timerAccess);

      for (unsigned int i = 0; i < timerQueue->getCount(); ++i)
      {
            const TimerEntry& e(timerQueue->operator[](i));
            if (e.semNum == sem->semNum && e.semId == id)
            {
                  timerQueue->remove(i);
                  return;
            }
      }
}

void stopTimers(void*)
{
      timerHolder.cleanup();
}

THREAD_ENTRY_DECLARE TimerEntry::timeThread(THREAD_ENTRY_PARAM)
{
      while (!stopThread)
      {
            int microSeconds = 0;
            {
                  MutexLockGuard guard(timerAccess);

                  const SINT64 cur = curTime();
                  while (timerQueue->getCount() > 0)
                  {
                        const TimerEntry& e(timerQueue->operator[](0));
                        if (e.fireTime <= cur)
                        {
                              for (;;)
                              {
                                    union semun arg;
                                    arg.val = 0;
                                    int ret = semctl(e.semId, e.semNum, SETVAL, arg);
                                    if (ret != -1)
                                          break;
                                    if (!SYSCALL_INTERRUPTED(errno))
                                    {
                                          break;
                                    }
                              }
                              timerQueue->remove((size_t) 0);
                        }
                        else
                        {
                              microSeconds = e.fireTime - cur;
                              break;
                        }
                  }
            }

            if (microSeconds)
            {
                  timerWakeup->tryEnter(0, microSeconds / 1000);
            }
            else
            {
                  timerWakeup->enter();
            }
      }

      timerFini->release();
      return 0;
}

} // namespace


SLONG ISC_event_clear(event_t* event)
{
/**************************************
 *
 *    I S C _ e v e n t _ c l e a r ( S Y S V )
 *
 **************************************
 *
 * 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.timerQueue[0].
 *
 **************************************/
      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);
}


void ISC_event_fini(event_t* event)
{
/**************************************
 *
 *    I S C _ e v e n t _ f i n i   ( S Y S V )
 *
 **************************************
 *
 * Functional description
 *    Discard an event object.
 *
 **************************************/
      IPC_TRACE(("ISC_event_fini set=%d num=%d\n", event->semSet, event->semNum));
      freeSem5(event);
}


int ISC_event_init(event_t* event)
{
/**************************************
 *
 *    I S C _ e v e n t _ i n i t   ( S Y S V )
 *
 **************************************
 *
 * Functional description
 *    Prepare an event object for use.
 *
 **************************************/

      event->event_count = 0;

      if (!getSem5(event))
      {
            IPC_TRACE(("ISC_event_init failed get sem %p\n", event));
            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)
      {
            iscLogStatus("event_init()",
                  (Arg::Gds(isc_sys_request) << Arg::Str("semctl") << SYS_ERR(errno)).value());
            return FB_FAILURE;
      }

      return FB_SUCCESS;
}


int ISC_event_post(event_t* event)
{
/**************************************
 *
 *    I S C _ e v e n t _ p o s t   ( S Y S V )
 *
 **************************************
 *
 * Functional description
 *    Post an event to wake somebody else up.
 *
 **************************************/
      union semun arg;

      ++event->event_count;

      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;
            }
      }

      return FB_SUCCESS;
}


int ISC_event_wait(event_t* event, SLONG value, const SLONG micro_seconds)
{
/**************************************
 *
 *    I S C _ e v e n t _ w a i t   ( S Y S V )
 *
 **************************************
 *
 * Functional description
 *    Wait on an event.  If timeout limit specified, return
 *    anyway after the timeout even if no event has
 *    happened.  If returning due to timeout, return
 *    FB_FAILURE else return FB_SUCCESS.
 *
 **************************************/
      //sigset_t mask, oldmask;

      // If we're not blocked, the rest is a gross waste of time
      if (!event_blocked(event, value))
            return FB_SUCCESS;

      // Set up timers if a timeout period was specified.

      //struct itimerval user_timer;
      //struct sigaction user_handler;
      //struct timeval cur_time;
      //struct timezone tzUnused;
      SINT64 timeout = 0;
      if (micro_seconds > 0)
      {
            timeout = addTimer(event, micro_seconds);
      }

      // Go into wait loop

      int ret = FB_SUCCESS;
      for (;;)
      {
            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);
            }

            if (micro_seconds > 0)
            {
                  // 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;
                  }
            }
      }

      // Cancel the handler.  We only get here if a timeout was specified.
      if (micro_seconds > 0)
      {
            delTimer(event);
      }

      return ret;
}

#else //not USE_SYS5SEMAPHORE

namespace {
int isPthreadError(int rc, const char* function)
{
      if (rc == 0)
            return 0;
      iscLogStatus("Pthread Error",
            (Arg::Gds(isc_sys_request) << Arg::Str(function) << Arg::Unix(rc)).value());
      return rc;
}
}
#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)

SLONG ISC_event_clear(event_t* event)
{
/**************************************
 *
 *    I S C _ e v e n t _ c l e a r ( P O S I X _ T H R E A D S )
 *
 **************************************
 *
 * 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.
 *
 **************************************/
      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;
}


void ISC_event_fini(event_t* event)
{
/**************************************
 *
 *    I S C _ e v e n t _ f i n i   ( P O S I X _ T H R E A D S )
 *
 **************************************
 *
 * Functional description
 *    Discard an event object.
 *
 **************************************/

      if (event->pid == getpid())
      {
            LOG_PTHREAD_ERROR(pthread_mutex_destroy(event->event_mutex));
            LOG_PTHREAD_ERROR(pthread_cond_destroy(event->event_cond));
      }
}


int ISC_event_init(event_t* event)
{
/**************************************
 *
 *    I S C _ e v e n t _ i n i t   ( P O S I X _ T H R E A D S )
 *
 **************************************
 *
 * Functional description
 *    Prepare an event object for use.
 *
 **************************************/
      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;
}


int ISC_event_post(event_t* event)
{
/**************************************
 *
 *    I S C _ e v e n t _ p o s t   ( P O S I X _ T H R E A D S )
 *
 **************************************
 *
 * Functional description
 *    Post an event to wake somebody else up.
 *
 **************************************/
      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)
      {
            gds__log ("ISC_event_post: pthread_cond_broadcast failed with errno = %d", ret);
            return FB_FAILURE;
      }

      return FB_SUCCESS;
}


int ISC_event_wait(event_t* event, const SLONG value, const SLONG micro_seconds)
{
/**************************************
 *
 *    I S C _ e v e n t _ w a i t   ( P O S I X _ T H R E A D S )
 *
 **************************************
 *
 * Functional description
 *    Wait on an event.  If timeout limit specified, return
 *    anyway after the timeout even if no event has
 *    happened.  If returning due to timeout, return
 *    FB_FAILURE else return FB_SUCCESS.
 *
 **************************************/

      // If we're not blocked, the rest is a gross waste of time

      if (!event_blocked(event, value))
            return FB_SUCCESS;

      // Set up timers if a timeout period was specified.

      struct timespec timer;
      if (micro_seconds > 0)
      {
            timer.tv_sec = time(NULL);
            timer.tv_sec += micro_seconds / 1000000;
            timer.tv_nsec = 1000 * (micro_seconds % 1000000);
      }

      int ret = FB_SUCCESS;
      pthread_mutex_lock(event->event_mutex);
      for (;;)
      {
            if (!event_blocked(event, value))
            {
                  ret = FB_SUCCESS;
                  break;
            }

            // 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.
            if (micro_seconds > 0)
            {
                  ret = pthread_cond_timedwait(event->event_cond, event->event_mutex, &timer);

#if (defined LINUX || defined DARWIN || defined HP11 || defined FREEBSD)
                  if (ret == ETIMEDOUT)
#else
                  if (ret == ETIME)
#endif
                  {

                        // The timer expired - see if the event occurred and return
                        // FB_SUCCESS or FB_FAILURE accordingly.

                        if (event_blocked(event, value))
                              ret = FB_FAILURE;
                        else
                              ret = FB_SUCCESS;
                        break;
                  }
            }
            else
                  ret = pthread_cond_wait(event->event_cond, event->event_mutex);
      }
      pthread_mutex_unlock(event->event_mutex);
      return ret;
}

#endif // USE_SYS5SEMAPHORE
#endif // USE_POSIX_THREADS


#ifdef WIN_NT
SLONG ISC_event_clear(event_t* event)
{
/**************************************
 *
 *    I S C _ e v e n t _ c l e a r ( W I N _ N T )
 *
 **************************************
 *
 * 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.
 *
 **************************************/

      ResetEvent((HANDLE) event->event_handle);

      return event->event_count + 1;
}


void ISC_event_fini(event_t* event)
{
/**************************************
 *
 *    I S C _ e v e n t _ f i n i   ( W I N _ N T )
 *
 **************************************
 *
 * Functional description
 *    Discard an event object.
 *
 **************************************/

      if (event->event_pid == process_id)
      {
            CloseHandle((HANDLE) event->event_handle);
      }
}


int ISC_event_init(event_t* event)
{
/**************************************
 *
 *    I S C _ e v e n t _ i n i t   ( W I N _ N T )
 *
 **************************************
 *
 * Functional description
 *    Prepare an event object for use.
 *
 **************************************/

      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;
}


int ISC_event_post(event_t* event)
{
/**************************************
 *
 *    I S C _ e v e n t _ p o s t   ( W I N _ N T )
 *
 **************************************
 *
 * Functional description
 *    Post an event to wake somebody else up.
 *
 **************************************/

      ++event->event_count;

      if (event->event_pid != process_id)
            return ISC_kill(event->event_pid, event->event_id, event->event_handle);

      return SetEvent((HANDLE) event->event_handle) ? FB_SUCCESS : FB_FAILURE;
}


int ISC_event_wait(event_t* event, const SLONG value, const SLONG micro_seconds)
{
/**************************************
 *
 *    I S C _ e v e n t _ w a i t   ( W I N _ N T )
 *
 **************************************
 *
 * Functional description
 *    Wait on an event.
 *
 **************************************/
      // If we're not blocked, the rest is a gross waste of time

      if (!event_blocked(event, value)) {
            return FB_SUCCESS;
      }

      // Go into wait loop

      const DWORD timeout = (micro_seconds > 0) ? micro_seconds / 1000 : INFINITE;

      for (;;)
      {
            if (!event_blocked(event, value)) {
                  return FB_SUCCESS;
            }

            const DWORD status = WaitForSingleObject(event->event_handle, timeout);

            if (status != WAIT_OBJECT_0)
            {
                  return FB_FAILURE;
            }
      }
}

#endif // WIN_NT


#ifdef UNIX
ULONG ISC_exception_post(ULONG sig_num, const TEXT* err_msg)
{
/**************************************
 *
 *    I S C _ e x c e p t i o n _ p o s t ( U N I X )
 *
 **************************************
 *
 * Functional description
 *     When we got a sync exception, fomulate the error code
 *     write it to the log file, and abort.
 *
 * 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,
 *   examples are gds__alloc, gds__log, etc... sprintf is safe on some BSD platforms,
 *   but not on Linux. This may result in lock-up during signal handling.
 *
 **************************************/
      // 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 = "";
      }

      TEXT* const log_msg = (TEXT *) gds__alloc(strlen(err_msg) + 256);
      // NOMEM: crash!
      log_msg[0] = '\0';

      switch (sig_num)
      {
      case SIGSEGV:
            sprintf(log_msg, "%s Segmentation Fault.\n"
                        "\t\tThe code attempted to access memory\n"
                        "\t\twithout privilege to do so.\n"
                        "\tThis exception will cause the Firebird server\n"
                        "\tto terminate abnormally.", err_msg);
            break;
      case SIGBUS:
            sprintf(log_msg, "%s Bus Error.\n"
                        "\t\tThe code caused a system bus error.\n"
                        "\tThis exception will cause the Firebird server\n"
                        "\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."
                        "\tThis exception will cause the Firebird server\n"
                        "\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."
                        "\tThis exception will cause the Firebird server\n"
                        "\tto terminate abnormally.", err_msg);
            break;
      default:
            sprintf(log_msg, "%s Unknown Exception.\n"
                        "\t\tException number %"ULONGFORMAT"."
                        "\tThis exception will cause the Firebird server\n"
                        "\tto terminate abnormally.", err_msg, sig_num);
            break;
      }

      if (err_msg)
      {
            gds__log(log_msg);
            gds__free(log_msg);
      }
      abort();

      return 0;   // compiler silencer
}
#endif // UNIX


#ifdef WIN_NT
ULONG ISC_exception_post(ULONG except_code, const TEXT* err_msg)
{
/**************************************
 *
 *    I S C _ e x c e p t i o n _ p o s t ( W I N _ N T )
 *
 **************************************
 *
 * Functional description
 *     When we got a sync exception, fomulate the error code
 *     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
 *     between abort() and exit(3).
 *
 **************************************/
      ULONG result = 0;
      bool is_critical = true;

      if (!err_msg)
      {
            err_msg = "";
      }

      TEXT* log_msg = (TEXT*) gds__alloc(strlen(err_msg) + 256);
      // NOMEM: crash!
      log_msg[0] = '\0';

      switch (except_code)
      {
      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"
                        "\tThis exception will cause the Firebird server\n"
                        "\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"
                        "\tThis exception will cause the Firebird server\n"
                        "\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"
                        "\tThis exception will cause the Firebird server\n"
                        "\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"
                        "\tThis exception will cause the Firebird server\n"
                        "\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"
                        "\tThis exception will cause the Firebird server\n"
                        "\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"
                        "\tThis exception will cause the Firebird server\n"
                        "\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"
                        "\tThis exception will cause the Firebird server\n"
                        "\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"
                        "\tThis exception will cause the Firebird server\n"
                        "\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"
                        "\tThis exception will cause the Firebird server\n"
                        "\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"
                        "\tThis exception will cause the Firebird server\n"
                        "\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"
                        "\tThis exception will cause the Firebird server\n"
                        "\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"
                        "\tThis exception will cause the Firebird server\n"
                        "\tto terminate abnormally.", err_msg);
            break;
      case EXCEPTION_STACK_OVERFLOW:
            status_exception::raise(Arg::Gds(isc_exception_stack_overflow));
            // This will never be called, but to be safe it's here
            result = (ULONG) EXCEPTION_CONTINUE_EXECUTION;
            is_critical = false;
            break;

      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:
            // 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
            result = EXCEPTION_CONTINUE_SEARCH;
            is_critical = false;
            break;
      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
            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);
            break;
      }

      if (is_critical)
      {
            gds__log(log_msg);
      }

      gds__free(log_msg);

      if (is_critical)
      {
            if (Config::getBugcheckAbort())
            {
                  // Pass exception to outer handler in case debugger is present to collect memory dump
                  return EXCEPTION_CONTINUE_SEARCH;
            }

            // 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.
            // This happens even if you run application as non-interactive service on
            // "server" OS like Windows Server 2003.
            exit(3);
      }

      return result;
}
#endif // WIN_NT

void SharedMemoryBase::removeMapFile()
{
#ifndef WIN_NT
      TEXT expanded_filename[MAXPATHLEN];
      gds__prefix_lock(expanded_filename, sh_mem_name);

      // 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);
#endif // WIN_NT
}

#ifdef UNIX

bool SharedMemoryBase::mapFile(Arg::StatusVector& statusVector,
                                             const TEXT* filename, ULONG length)
{
/**************************************
 *
 *    I S C _ m a p _ f i l e       ( U N I X - m m a p )
 *
 **************************************
 *
 * 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).
 *
 **************************************/

      setHeader(NULL);

      TEXT expanded_filename[MAXPATHLEN];
      gds__prefix_lock(expanded_filename, filename);

      // 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
      // locking. The race condition is caused as the conversion of a EXCLUSIVE
      // lock to a LCK_SHARED lock is not atomic

      TEXT init_filename[MAXPATHLEN];
      gds__prefix_lock(init_filename, INIT_FILE);

      const bool trunc_flag = (length != 0);

      // open the init lock file
      MutexLockGuard guard(openFdInit);

#ifdef USE_SYS5SEMAPHORE
      if (fd_init < 0)
#else
      int
#endif
            fd_init = os_utils::openCreateSharedFile(init_filename, 0);
      if (fd_init == -1)
      {
            error(statusVector, "open", errno);
            return false;
      }

      // get an exclusive lock on the INIT file with blocking
      FileLock initLock(statusVector, fd_init);
#ifdef USE_SYS5SEMAPHORE
      initLock.setDtorMode(FileLock::OPENED);
#endif
      if (!initLock.exclusive())
      {
            return false;
      }

      // init file is locked - no races possible later in this function

#ifdef USE_SYS5SEMAPHORE
      if (fdSem < 0)
      {
            TEXT sem_filename[MAXPATHLEN];
            gds__prefix_lock(sem_filename, SEM_FILE);
            const int f = os_utils::openCreateSharedFile(sem_filename, 0);
            if (f == -1)
            {
                  error(statusVector, "open", errno);
                  return false;
            }
            void* sTab = mmap(0, sizeof(SemTable), PROT_READ | PROT_WRITE, MAP_SHARED, f, 0);
            if ((U_IPTR) sTab == (U_IPTR) -1)
            {
                  error(statusVector, "mmap", errno);
                  return false;
            }

            fdSem = f;
            semTable = (SemTable*) sTab;
            initCache();
      }
      fb_assert(semTable);

      FileLock semLock(statusVector, fdSem, FileLock::OPENED);

      if (semLock.tryExclusive())
      {
            semTable->init();
      }
      if (!semLock.shared())
      {
            return false;
      }
#endif

      // open the file to be inited
      const int fd = os_utils::openCreateSharedFile(expanded_filename, 0);
      if (fd == -1)
      {
            error(statusVector, "open", errno);
            return false;
      }

      // create lock in order to have file autoclosed on error
      FileLock mainLock(statusVector, fd);

      if (length == 0)
      {
            // Get and use the existing length of the shared segment
            struct stat file_stat;
            if (fstat(fd, &file_stat) == -1)
            {
                  error(statusVector, "fstat", errno);
                  return false;
            }
            length = file_stat.st_size;

            if (length == 0)
            {
                  // keep old text of message here -  will be assigned a bit later
                  error(statusVector, "shmem_data->sh_mem_length_mapped is 0", 0);
                  return false;
            }
      }

      // map file to memory
      void* const address = mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
      if ((U_IPTR) address == (U_IPTR) -1)
      {
            error(statusVector, "mmap", errno);
            return false;
      }

#ifdef USE_SYS5SEMAPHORE
      // register mapped file
      // this class is needed to auto-unregister it in case of failure
      class sfHolder
      {
      public:
            explicit sfHolder(const SharedFile& sf) : pop(true)
            {
                  SharedFile::push(sf);
            }

            void materialize()
            {
                  pop = false;
            }

            ~sfHolder()
            {
                  if (pop)
                  {
                        SharedFile::pop();
                  }
            }
      private:
            bool pop;
      };
      sfHolder holder(SharedFile(expanded_filename, address, length));
#endif

      MemoryHeader* hdr = (MemoryHeader*) address;
      setHeader(hdr);
      sh_mem_length_mapped = length;
      sh_mem_handle = fd;
      strcpy(sh_mem_name, filename);

#if defined(HAVE_OBJECT_MAP) && (!defined(USE_SYS5SEMAPHORE))
      sh_mem_mutex = (mtx*) mapObject(statusVector, OFFSET(MemoryHeader*, mhb_mutex), sizeof(mtx));
      if (!sh_mem_mutex)
      {
            munmap(address, length);
            setHeader(NULL);
            return false;
      }
#else
      sh_mem_mutex = &hdr->mhb_mutex;
#endif

      // Try to get an exclusive lock on the lock file.  This will
      // fail if somebody else has the exclusive or shared lock

      if (mainLock.tryExclusive())
      {
            if (trunc_flag)
                  ftruncate(fd, length);

            if (initialize(true))
            {
                  int mtxState = ISC_mutex_init(sh_mem_mutex);
                  if (mtxState != 0)
                  {
                        mutexBug(mtxState, "ISC_init_mutex");
                  }

                  if (!mainLock.tryShared())
                  {
                        munmap(address, length);
                        setHeader(NULL);
                        return false;
                  }
            }
      }
      else
      {
            if (initialize(false))
            {
                  if (!mainLock.tryShared())
                  {
                        munmap(address, length);
                        setHeader(NULL);
                        return false;
                  }
            }
      }

      // keep opened the shared file_decriptor
      mainLock.setDtorMode(FileLock::LOCKED);
#ifdef USE_SYS5SEMAPHORE
      // keep shared lock before last shared memory region unmapped
      semLock.setDtorMode(FileLock::LOCKED);
      ++sharedCount;
      // keep registered mapped file permanently
      holder.materialize();
#endif

      return true;
}

#endif // UNIX


#ifdef WIN_NT
bool SharedMemoryBase::mapFile(Arg::StatusVector& statusVector,
                                             const TEXT* filename, ULONG length)
{
/**************************************
 *
 *    I S C _ m a p _ f i l e       ( W I N _ N T )
 *
 **************************************
 *
 * 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).
 *
 **************************************/

      setHeader(NULL);

      ISC_mutex_init(&sh_mem_winMutex, filename);
      sh_mem_mutex = &sh_mem_winMutex;

      HANDLE file_handle;
      HANDLE event_handle = 0;
      int retry_count = 0;

      TEXT expanded_filename[MAXPATHLEN];
      gds__prefix_lock(expanded_filename, filename);

      const bool trunc_flag = (length != 0);
      bool init_flag = false;

      // retry to attach to mmapped file if the process initializing dies during initialization.

  retry:
      if (retry_count++ > 0)
            THD_sleep(10);

      file_handle = CreateFile(expanded_filename,
                                           GENERIC_READ | GENERIC_WRITE,
                                           FILE_SHARE_READ | FILE_SHARE_WRITE,
                                           NULL,
                                           OPEN_ALWAYS,
                                           FILE_ATTRIBUTE_NORMAL,
                                           NULL);
      DWORD err = GetLastError();
      if (file_handle == INVALID_HANDLE_VALUE)
      {
            if (err == ERROR_SHARING_VIOLATION)
                  goto retry;

            error(statusVector, "CreateFile", GetLastError());
            return false;
      }

      // Check if file already exists

      const bool file_exists = (err == ERROR_ALREADY_EXISTS);

      // Create an event that can be used to determine if someone has already
      // initialized shared memory.

      TEXT object_name[MAXPATHLEN];
      if (!make_object_name(object_name, sizeof(object_name), filename, "_event"))
      {
            error(statusVector, "make_object_name", GetLastError());
            CloseHandle(file_handle);
            return false;
      }

      if (!init_flag)
      {
            event_handle = CreateEvent(ISC_get_security_desc(), TRUE, FALSE, object_name);
            if (!event_handle)
            {
                  error(statusVector, "CreateEvent", GetLastError());
                  CloseHandle(file_handle);
                  return false;
            }

            init_flag = (GetLastError() != ERROR_ALREADY_EXISTS);

            if (init_flag && false)
            {
                  CloseHandle(event_handle);
                  CloseHandle(file_handle);
                  statusVector << Arg::Gds(isc_unavailable);
                  return false;
            }
      }

      if (length == 0)
      {
            // Get and use the existing length of the shared segment

            if ((length = GetFileSize(file_handle, NULL)) == -1)
            {
                  error(statusVector, "GetFileSize", GetLastError());
                  CloseHandle(event_handle);
                  CloseHandle(file_handle);
                  return false;
            }
      }

      // 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.

      CloseHandle(file_handle);

      if (!init_flag)
      {
            // Wait for 10 seconds.  Then retry

            const DWORD ret_event = WaitForSingleObject(event_handle, 10000);

            // If we timed out, just retry.  It is possible that the
            // process doing the initialization died before setting the event.

            if (ret_event == WAIT_TIMEOUT)
            {
                  CloseHandle(event_handle);
                  if (retry_count > 10)
                  {
                        error(statusVector, "WaitForSingleObject", 0);
                        return false;
                  }
                  goto retry;
            }
      }

      DWORD fdw_create;
      if (init_flag && file_exists && trunc_flag)
            fdw_create = TRUNCATE_EXISTING;
      else
            fdw_create = OPEN_ALWAYS;

      file_handle = CreateFile(expanded_filename,
                                           GENERIC_READ | GENERIC_WRITE,
                                           FILE_SHARE_READ | FILE_SHARE_WRITE,
                                           NULL,
                                           fdw_create,
                                           FILE_ATTRIBUTE_NORMAL,
                                           NULL);
      if (file_handle == INVALID_HANDLE_VALUE)
      {
            const DWORD err = GetLastError();

            if ((err == ERROR_SHARING_VIOLATION) || (err == ERROR_FILE_NOT_FOUND && fdw_create == TRUNCATE_EXISTING))
            {
                  if (!init_flag) {
                        CloseHandle(event_handle);
                  }
                  goto retry;
            }

            if (err == ERROR_USER_MAPPED_FILE && init_flag && file_exists && trunc_flag)
                  statusVector << Arg::Gds(isc_instance_conflict);
            else
                  error(statusVector, "CreateFile", err);

            CloseHandle(event_handle);
            return false;
      }

      if (!init_flag)
      {
            if ((GetLastError() != ERROR_ALREADY_EXISTS) || SetFilePointer(file_handle, 0, NULL, FILE_END) == 0)
            {
                  CloseHandle(event_handle);
                  CloseHandle(file_handle);
                  goto retry;
            }
      }

      // 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.

      if (!make_object_name(object_name, sizeof(object_name), filename, "_mapping"))
      {
            error(statusVector, "make_object_name", GetLastError());
            CloseHandle(event_handle);
            CloseHandle(file_handle);
            return false;
      }

      HANDLE header_obj = CreateFileMapping(INVALID_HANDLE_VALUE,
                                                              ISC_get_security_desc(),
                                                              PAGE_READWRITE,
                                                              0, 2 * sizeof(ULONG),
                                                              object_name);
      if (header_obj == NULL)
      {
            error(statusVector, "CreateFileMapping", GetLastError());
            CloseHandle(event_handle);
            CloseHandle(file_handle);
            return false;
      }

      if (!init_flag && GetLastError() != ERROR_ALREADY_EXISTS)
      {
            // 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;
      }

      ULONG* const header_address = (ULONG*) MapViewOfFile(header_obj, FILE_MAP_WRITE, 0, 0, 0);

      if (header_address == NULL)
      {
            error(statusVector, "MapViewOfFile", GetLastError());
            CloseHandle(header_obj);
            CloseHandle(event_handle);
            CloseHandle(file_handle);
            return false;
      }

      // Set or get the true length of the file depending on whether or not we are the first user.

      if (init_flag)
      {
            header_address[0] = length;
            header_address[1] = 0;
      }
      else
            length = header_address[0];

      // Create the real file mapping object.

      TEXT mapping_name[64]; // enough for int32 as text
      sprintf(mapping_name, "_mapping_%"ULONGFORMAT, header_address[1]);

      if (!make_object_name(object_name, sizeof(object_name), filename, mapping_name))
      {
            error(statusVector, "make_object_name", GetLastError());
            UnmapViewOfFile(header_address);
            CloseHandle(header_obj);
            CloseHandle(event_handle);
            CloseHandle(file_handle);
            return false;
      }

      HANDLE file_obj = CreateFileMapping(file_handle,
                                                            ISC_get_security_desc(),
                                                            PAGE_READWRITE,
                                                            0, length,
                                                            object_name);
      if (file_obj == NULL)
      {
            error(statusVector, "CreateFileMapping", GetLastError());
            UnmapViewOfFile(header_address);
            CloseHandle(header_obj);
            CloseHandle(event_handle);
            CloseHandle(file_handle);
            return false;
      }

      UCHAR* const address = (UCHAR*) MapViewOfFile(file_obj, FILE_MAP_WRITE, 0, 0, 0);

      if (address == NULL)
      {
            error(statusVector, "MapViewOfFile", GetLastError());
            CloseHandle(file_obj);
            UnmapViewOfFile(header_address);
            CloseHandle(header_obj);
            CloseHandle(event_handle);
            CloseHandle(file_handle);
            return false;
      }

      MemoryHeader* hdr = (MemoryHeader*) address;
      setHeader(hdr);
      sh_mem_length_mapped = length;

      if (!sh_mem_length_mapped)
      {
            error(statusVector, "sh_mem_length_mapped is 0", 0);
            return false;
      }

      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);

      initialize(init_flag);

      if (init_flag)
      {
            FlushViewOfFile(address, 0);

            DWORD err = 0;
            if (SetFilePointer(sh_mem_handle, length, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ||
                  !SetEndOfFile(sh_mem_handle) ||
                  !FlushViewOfFile(address, 0))
            {
                  err = GetLastError();
            }

            SetEvent(event_handle);
            if (err)
            {
                  error(statusVector, "SetFilePointer", err);
                  return false;
            }
      }

      return true;
}
#endif


#ifdef HAVE_MMAP

UCHAR* SharedMemoryBase::mapObject(Arg::StatusVector& statusVector, ULONG object_offset, ULONG object_length)
{
/**************************************
 *
 *    I S C _ m a p _ o b j e c t
 *
 **************************************
 *
 * Functional description
 *    Try to map an object given a file mapping.
 *
 **************************************/

      // Get system page size as this is the unit of mapping.

#ifdef SOLARIS
      const long ps = sysconf(_SC_PAGESIZE);
      if (ps == -1)
      {
            error(statusVector, "sysconf", errno);
            return NULL;
      }
#else
      const int ps = getpagesize();
      if (ps == -1)
      {
            error(statusVector, "getpagesize", errno);
            return NULL;
      }
#endif
      const ULONG page_size = (ULONG) ps;

      // 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;
      int fd = sh_mem_handle;

      UCHAR* address = (UCHAR*) mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, start);

      if ((U_IPTR) address == (U_IPTR) -1)
      {
            error(statusVector, "mmap", errno);
            return NULL;
      }

      // Return the virtual address of the mapped object.

      IPC_TRACE(("ISC_map_object in %p to %p %p\n", shmem_data->sh_mem_address, address, address + length));

      return address + (object_offset - start);
}


void SharedMemoryBase::unmapObject(Arg::StatusVector& statusVector, UCHAR** object_pointer, ULONG object_length)
{
/**************************************
 *
 *    I S C _ u n m a p _ o b j e c t
 *
 **************************************
 *
 * Functional description
 *    Try to unmap an object given a file mapping.
 *    Zero the object pointer after a successful unmap.
 *
 **************************************/
      // Get system page size as this is the unit of mapping.

#ifdef SOLARIS
      const long ps = sysconf(_SC_PAGESIZE);
      if (ps == -1)
      {
            error(statusVector, "sysconf", errno);
            return;
      }
#else
      const int ps = getpagesize();
      if (ps == -1)
      {
            error(statusVector, "getpagesize", errno);
            return;
      }
#endif
      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;
}
#endif // HAVE_MMAP


#ifdef WIN_NT

UCHAR* SharedMemoryBase::mapObject(Arg::StatusVector& statusVector,
                                                   ULONG object_offset,
                                                   ULONG object_length)
{
/**************************************
 *
 *    I S C _ m a p _ o b j e c t
 *
 **************************************
 *
 * Functional description
 *    Try to map an object given a file mapping.
 *
 **************************************/

      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));
}


void SharedMemoryBase::unmapObject(Arg::StatusVector& statusVector,
                                                   UCHAR** object_pointer, ULONG /*object_length*/)
{
/**************************************
 *
 *    I S C _ u n m a p _ o b j e c t
 *
 **************************************
 *
 * Functional description
 *    Try to unmap an object given a file mapping.
 *    Zero the object pointer after a successful unmap.
 *
 **************************************/
      SYSTEM_INFO sys_info;
      GetSystemInfo(&sys_info);
      const size_t page_size = sys_info.dwAllocationGranularity;

      // Compute the start and end page-aligned offsets which
      // contain the object being mapped.

      const UCHAR* start = (UCHAR*) ((U_IPTR) *object_pointer & ~(page_size - 1));
      if (!UnmapViewOfFile(start))
      {
            error(statusVector, "UnmapViewOfFile", GetLastError());
            return;
      }

      *object_pointer = NULL;
}
#endif


#ifdef USE_POSIX_THREADS

#ifdef USE_SYS5SEMAPHORE



int ISC_mutex_init(struct mtx* mutex)
{
/**************************************
 *
 *    I S C _ m u t e x _ i n i t   ( S Y S V )
 *
 **************************************
 *
 * Functional description
 *    Initialize a mutex.
 *
 **************************************/

      if (!getSem5(mutex))
      {
            return FB_FAILURE;
      }

      union semun arg;
      arg.val = 1;
      int state = semctl(mutex->getId(), mutex->semNum, SETVAL, arg);
      if (state == -1)
      {
            return errno;
      }

      return 0;
}


int ISC_mutex_lock(struct mtx* mutex)
{
/**************************************
 *
 *    I S C _ m u t e x _ l o c k   ( S Y S V )
 *
 **************************************
 *
 * Functional description
 *    Seize a mutex.
 *
 **************************************/
      struct sembuf sop;
      sop.sem_num = mutex->semNum;
      sop.sem_op = -1;
      sop.sem_flg = SEM_UNDO;

      for (;;)
      {
            int state = semop(mutex->getId(), &sop, 1);
            if (state != -1)
                  break;
            if (!SYSCALL_INTERRUPTED(errno))
                  return errno;
      }

      return 0;
}


int ISC_mutex_lock_cond(struct mtx* mutex)
{
/**************************************
 *
 *    I S C _ m u t e x _ l o c k _ c o n d ( S Y S V )
 *
 **************************************
 *
 * Functional description
 *    Conditionally seize a mutex.
 *
 **************************************/
      struct sembuf sop;
      sop.sem_num = mutex->semNum;
      sop.sem_op = -1;
      sop.sem_flg = SEM_UNDO | IPC_NOWAIT;

      for (;;)
      {
            int state = semop(mutex->getId(), &sop, 1);
            if (state != -1)
                  break;
            if (!SYSCALL_INTERRUPTED(errno))
                  return errno;
      }

      return 0;
}


int ISC_mutex_unlock(struct mtx* mutex)
{
/**************************************
 *
 *    I S C _ m u t e x _ u n l o c k ( S Y S V )
 *
 **************************************
 *
 * Functional description
 *    Release a mutex.
 *
 **************************************/
      struct sembuf sop;
      sop.sem_num = mutex->semNum;
      sop.sem_op = 1;
      sop.sem_flg = SEM_UNDO;

      for (;;)
      {
            int state = semop(mutex->getId(), &sop, 1);
            if (state != -1)
                  break;
            if (!SYSCALL_INTERRUPTED(errno))
                  return errno;
      }

      return 0;
}

#else // not 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(). Here is a hack to deal with this broken error reporting.
#define BUGGY_LINUX_MUTEX
#endif

#ifdef BUGGY_LINUX_MUTEX
static volatile bool staticBugFlag = false;
#endif

int ISC_mutex_init(struct mtx* mutex)
{
/**************************************
 *
 *    I S C _ m u t e x _ i n i t   ( P O S I X _ T H R E A D S )
 *
 **************************************
 *
 * Functional description
 *    Initialize a mutex.
 *
 **************************************/

#ifdef BUGGY_LINUX_MUTEX
  do
  {
      bool bugFlag = staticBugFlag;
#endif

      pthread_mutexattr_t mattr;

      PTHREAD_ERRNO(pthread_mutexattr_init(&mattr));
#ifdef PTHREAD_PROCESS_SHARED
      PTHREAD_ERRNO(pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED));
#else
#error Your system must support PTHREAD_PROCESS_SHARED to use 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(mutex->mtx_mutex, 0, sizeof(pthread_mutex_t));
      //int state = LOG_PTHREAD_ERROR(pthread_mutex_init(mutex->mtx_mutex, &mattr));
      int state = pthread_mutex_init(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;
      }

      return state;     // To avoid declaring 'state' out of loop
  } while (false);

  return 0;             // compiler warning silencer
#else

  return state;
#endif
}


int ISC_mutex_lock(struct mtx* mutex)
{
/**************************************
 *
 *    I S C _ m u t e x _ l o c k   ( P O S I X _ T H R E A D S )
 *
 **************************************
 *
 * Functional description
 *    Seize a mutex.
 *
 **************************************/

      int state = pthread_mutex_lock(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(mutex->mtx_mutex));
            state = 0;
      }
#endif
      return state;
}


int ISC_mutex_lock_cond(struct mtx* mutex)
{
/**************************************
 *
 *    I S C _ m u t e x _ l o c k _ c o n d     ( P O S I X _ T H R E A D S )
 *
 **************************************
 *
 * Functional description
 *    Conditionally seize a mutex.
 *
 **************************************/

      return pthread_mutex_trylock(mutex->mtx_mutex);
}


int ISC_mutex_unlock(struct mtx* mutex)
{
/**************************************
 *
 *    I S C _ m u t e x _ u n l o c k           ( P O S I X _ T H R E A D S )
 *
 **************************************
 *
 * Functional description
 *    Release a mutex.
 *
 **************************************/

      return pthread_mutex_unlock(mutex->mtx_mutex);
}

#endif // USE_SYS5SEMAPHORE

#endif // USE_POSIX_THREADS


#ifdef WIN_NT

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;

static SLONG pid = 0;

typedef WINBASEAPI BOOL (WINAPI *pfnSwitchToThread) ();
static inline BOOL switchToThread()
{
      static pfnSwitchToThread fnSwitchToThread = NULL;
      static bool bInit = false;

      if (!bInit)
      {
            HMODULE hLib = GetModuleHandle("kernel32.dll");
            if (hLib)
                  fnSwitchToThread = (pfnSwitchToThread) GetProcAddress(hLib, "SwitchToThread");

            bInit = true;
      }

      BOOL res = FALSE;

      if (fnSwitchToThread)
      {
            const HANDLE hThread = GetCurrentThread();
            SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);

            res = (*fnSwitchToThread)();

            SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL);
      }

      return res;
}


// MinGW has the wrong declaration for the operating system function.
#if defined __GNUC__
// Cast away volatile
#define FIX_TYPE(arg) const_cast<LPLONG>(arg)
#else
#define FIX_TYPE(arg) arg
#endif


static inline void lockSharedSection(volatile FAST_MUTEX_SHARED_SECTION* lpSect, ULONG SpinCount)
{
      while (InterlockedExchange(FIX_TYPE(&lpSect->lSpinLock), 1) != 0)
      {
            ULONG j = SpinCount;
            while (j != 0)
            {
                  if (lpSect->lSpinLock == 0)
                        goto next;
                  j--;
            }
            switchToThread();
next:;
      }
}

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)
      {
            if (dwMilliseconds == 0)
            {
                  if (!tryLockSharedSection(lpSect))
                        return WAIT_TIMEOUT;
            }
            else {
                  lockSharedSection(lpSect, lpMutex->lSpinCount);
            }

            if (lpSect->lAvailable > 0)
            {
                  lpSect->lAvailable--;
#ifdef _DEBUG
                  lpSect->dwThreadId = GetCurrentThreadId();
#endif
                  lpSect->lOwnerPID = pid;
                  unlockSharedSection(lpSect);
                  return WAIT_OBJECT_0;
            }

#ifdef _DEBUG
            if (lpSect->dwThreadId == GetCurrentThreadId())
                  DebugBreak();
#endif
            if (dwMilliseconds == 0)
            {
                  unlockSharedSection(lpSect);
                  return WAIT_TIMEOUT;
            }

            InterlockedIncrement(FIX_TYPE(&lpSect->lThreadsWaiting));
            unlockSharedSection(lpSect);

            // TODO actual timeout can be of any length
            const DWORD tm = (dwMilliseconds == INFINITE || dwMilliseconds > 5000) ? 5000 : dwMilliseconds;
            const DWORD dwResult = WaitForSingleObject(lpMutex->hEvent, tm);

            InterlockedDecrement(FIX_TYPE(&lpSect->lThreadsWaiting));

            if (dwMilliseconds != INFINITE)
                  dwMilliseconds -= tm;

//          if (dwResult != WAIT_OBJECT_0)
//                return dwResult;

            if (dwResult == WAIT_OBJECT_0)
                  continue;
            if (dwResult == WAIT_ABANDONED)
                  return dwResult;
            if (dwResult == WAIT_TIMEOUT && !dwMilliseconds)
                  return dwResult;

            lockSharedSection(lpSect, lpMutex->lSpinCount);
            if (lpSect->lOwnerPID > 0 && !lpSect->lAvailable)
            {
                  if (!ISC_check_process_existence(lpSect->lOwnerPID))
                  {
#ifdef DEBUG
                        gds__log("enterFastMutex: dead process detected, pid = %d", lpSect->lOwnerPID);
#endif
                        lpSect->lOwnerPID = 0;
                        lpSect->lAvailable++;
                  }
            }
            unlockSharedSection(lpSect);
      }
}

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);
      lpSect->lOwnerPID = -pid;
      unlockSharedSection(lpSect);

      return true;
}

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;
}

static bool initializeFastMutex(FAST_MUTEX* lpMutex, LPSECURITY_ATTRIBUTES lpAttributes,
                                                BOOL bInitialState, LPCSTR lpName)
{
      if (pid == 0)
            pid = GetCurrentProcessId();

      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);

      char sz[MAXPATHLEN];
      if (lpName)
      {
            sprintf(sz, FAST_MUTEX_EVT_NAME, lpName);
            name = sz;
      }

#ifdef DONT_USE_FAST_MUTEX
      lpMutex->lpSharedInfo = NULL;
      lpMutex->hEvent = CreateMutex(lpAttributes, bInitialState, name);
      return (lpMutex->hEvent != NULL);
#else
      lpMutex->hEvent = CreateEvent(lpAttributes, FALSE, FALSE, name);
      DWORD dwLastError = GetLastError();

      if (lpMutex->hEvent)
      {
            if (lpName)
                  sprintf(sz, FAST_MUTEX_MAP_NAME, lpName);

            lpMutex->hFileMap = CreateFileMapping(
                  INVALID_HANDLE_VALUE,
                  lpAttributes,
                  PAGE_READWRITE,
                  0,
                  sizeof(FAST_MUTEX_SHARED_SECTION),
                  name);

            dwLastError = GetLastError();

            if (lpMutex->hFileMap)
            {
                  lpMutex->lpSharedInfo = (FAST_MUTEX_SHARED_SECTION*)
                        MapViewOfFile(lpMutex->hFileMap, FILE_MAP_WRITE, 0, 0, 0);

                  if (lpMutex->lpSharedInfo)
                  {
                        if (dwLastError != ERROR_ALREADY_EXISTS)
                        {
                              lpMutex->lpSharedInfo->lSpinLock = 0;
                              lpMutex->lpSharedInfo->lThreadsWaiting = 0;
                              lpMutex->lpSharedInfo->lAvailable = bInitialState ? 0 : 1;
                              lpMutex->lpSharedInfo->lOwnerPID = bInitialState ? pid : 0;
                              InterlockedExchange(FIX_TYPE(&lpMutex->lpSharedInfo->fInitialized), 1);
                        }
                        else
                        {
                              while (!lpMutex->lpSharedInfo->fInitialized)
                                    switchToThread();
                        }

                        SetLastError(dwLastError);
                        return true;
                  }
                  CloseHandle(lpMutex->hFileMap);
            }
            CloseHandle(lpMutex->hEvent);
      }

      SetLastError(dwLastError);
      return false;
#endif // DONT_USE_FAST_MUTEX
}

#ifdef NOT_USED_OR_REPLACED
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);

      char sz[MAXPATHLEN];
      if (lpName)
      {
            sprintf(sz, FAST_MUTEX_EVT_NAME, lpName);
            name = sz;
      }

      lpMutex->hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, name);

      DWORD dwLastError = GetLastError();

      if (lpMutex->hEvent)
      {
            if (lpName)
                  sprintf(sz, FAST_MUTEX_MAP_NAME, lpName);

            lpMutex->hFileMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, name);

            dwLastError = GetLastError();

            if (lpMutex->hFileMap)
            {
                  lpMutex->lpSharedInfo = (FAST_MUTEX_SHARED_SECTION*)
                        MapViewOfFile(lpMutex->hFileMap, FILE_MAP_WRITE, 0, 0, 0);

                  if (lpMutex->lpSharedInfo)
                        return true;

                  CloseHandle(lpMutex->hFileMap);
            }
            CloseHandle(lpMutex->hEvent);
      }

      SetLastError(dwLastError);
      return false;
}
#endif

static inline void setFastMutexSpinCount(FAST_MUTEX* lpMutex, ULONG SpinCount)
{
      lpMutex->lSpinCount = SpinCount;
}


int ISC_mutex_init(struct mtx* mutex, const TEXT* mutex_name)
{
/**************************************
 *
 *    I S C _ m u t e x _ i n i t   ( W I N _ N T )
 *
 **************************************
 *
 * Functional description
 *    Initialize a mutex.
 *
 **************************************/
      char name_buffer[MAXPATHLEN];

      if (!make_object_name(name_buffer, sizeof(name_buffer), mutex_name, "_mutex"))
      {
            return FB_FAILURE;
      }

      if (initializeFastMutex(&mutex->mtx_fast, ISC_get_security_desc(), FALSE, name_buffer))
            return FB_SUCCESS;

      fb_assert(GetLastError() != 0);
      return GetLastError();
}


void ISC_mutex_fini(struct mtx *mutex)
{
/**************************************
 *
 *    m u t e x _ f i n i ( W I N _ N T )
 *
 **************************************
 *
 * Functional description
 *    Destroy a mutex.
 *
 **************************************/
      if (mutex->mtx_fast.lpSharedInfo)
            deleteFastMutex(&mutex->mtx_fast);
}


int ISC_mutex_lock(struct mtx* mutex)
{
/**************************************
 *
 *    I S C _ m u t e x _ l o c k   ( W I N _ N T )
 *
 **************************************
 *
 * Functional description
 *    Seize a mutex.
 *
 **************************************/

      const DWORD status = (mutex->mtx_fast.lpSharedInfo) ?
            enterFastMutex(&mutex->mtx_fast, INFINITE) :
                  WaitForSingleObject(mutex->mtx_fast.hEvent, INFINITE);

    return (status == WAIT_OBJECT_0 || status == WAIT_ABANDONED) ? FB_SUCCESS : FB_FAILURE;
}


int ISC_mutex_lock_cond(struct mtx* mutex)
{
/**************************************
 *
 *    I S C _ m u t e x _ l o c k _ c o n d     ( W I N _ N T )
 *
 **************************************
 *
 * Functional description
 *    Conditionally seize a mutex.
 *
 **************************************/

      const DWORD status = (mutex->mtx_fast.lpSharedInfo) ?
            enterFastMutex(&mutex->mtx_fast, 0) : WaitForSingleObject(mutex->mtx_fast.hEvent, 0L);

    return (status == WAIT_OBJECT_0 || status == WAIT_ABANDONED) ? FB_SUCCESS : FB_FAILURE;
}


int ISC_mutex_unlock(struct mtx* mutex)
{
/**************************************
 *
 *    I S C _ m u t e x _ u n l o c k           ( W I N _ N T )
 *
 **************************************
 *
 * Functional description
 *    Release a mutex.
 *
 **************************************/

      if (mutex->mtx_fast.lpSharedInfo) {
            return !leaveFastMutex(&mutex->mtx_fast);
      }

      return !ReleaseMutex(mutex->mtx_fast.hEvent);
}


void ISC_mutex_set_spin_count (struct mtx *mutex, ULONG spins)
{
      if (mutex->mtx_fast.lpSharedInfo)
            setFastMutexSpinCount(&mutex->mtx_fast, spins);
}

#endif // WIN_NT


#ifdef UNIX
#ifdef HAVE_MMAP
#define ISC_REMAP_FILE_DEFINED
bool SharedMemoryBase::remapFile(Arg::StatusVector& statusVector, ULONG new_length, bool flag)
{
/**************************************
 *
 *    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.
 *
 **************************************/
      if (!new_length)
      {
            error(statusVector, "Zero new_length is requested", 0);
            return false;
      }

      if (flag)
            ftruncate(sh_mem_handle, new_length);

      MemoryHeader* const address = (MemoryHeader*)
            mmap(0, new_length, PROT_READ | PROT_WRITE, MAP_SHARED, sh_mem_handle, 0);
      if ((U_IPTR) address == (U_IPTR) -1)
      {
            error(statusVector, "mmap() failed", errno);
            return false;
      }

      munmap((char*) getHeader(), sh_mem_length_mapped);

#ifdef USE_SYS5SEMAPHORE
      SharedFile::remap(getHeader(), address, new_length);
#endif
      IPC_TRACE(("ISC_remap_file %p to %p %d\n", getHeader(), address, new_length));

      setHeader(address);
      sh_mem_length_mapped = new_length;

#if (!defined(HAVE_OBJECT_MAP)) || defined(USE_SYS5SEMAPHORE)
      sh_mem_mutex = &getHeader()->mhb_mutex;
#endif

      return address;
}
#endif // HAVE_MMAP
#endif // UNIX


#ifdef WIN_NT
#define ISC_REMAP_FILE_DEFINED
bool SharedMemoryBase::remapFile(Arg::StatusVector& statusVector,
                                                 ULONG new_length, bool flag)
{
/**************************************
 *
 *    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)
      {
            if (SetFilePointer(sh_mem_handle, new_length, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ||
                  !SetEndOfFile(sh_mem_handle) ||
                  !FlushViewOfFile(getHeader(), 0))
            {
                  error(statusVector, "SetFilePointer", GetLastError());
                  return NULL;
            }
      }

      /* 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.
      */

      HANDLE file_obj = NULL;

      while (true)
      {
            TEXT mapping_name[64]; // enough for int32 as text
            sprintf(mapping_name, "_mapping_%"ULONGFORMAT, sh_mem_hdr_address[1] + 1);

            TEXT object_name[MAXPATHLEN];
            if (!make_object_name(object_name, sizeof(object_name), sh_mem_name, mapping_name))
                  break;

            file_obj = CreateFileMapping(sh_mem_handle,
                                                       ISC_get_security_desc(),
                                                       PAGE_READWRITE,
                                                       0, new_length,
                                                       object_name);

            if (!(GetLastError() == ERROR_ALREADY_EXISTS && flag))
                  break;

            CloseHandle(file_obj);
            file_obj = NULL;
            sh_mem_hdr_address[1]++;
      }

      if (file_obj == NULL)
      {
            error(statusVector, "CreateFileMapping", GetLastError());
            return NULL;
      }

      MemoryHeader* const address = (MemoryHeader*) MapViewOfFile(file_obj, FILE_MAP_WRITE, 0, 0, 0);

      if (address == NULL)
      {
            error(statusVector, "MapViewOfFile", GetLastError());
            CloseHandle(file_obj);
            return NULL;
      }

      if (flag)
      {
            sh_mem_hdr_address[0] = new_length;
            sh_mem_hdr_address[1]++;
      }

      UnmapViewOfFile(getHeader());
      CloseHandle(sh_mem_object);

      setHeader(address);
      sh_mem_length_mapped = new_length;
      sh_mem_object = file_obj;

      if (!sh_mem_length_mapped)
      {
            error(statusVector, "sh_mem_length_mapped is 0", 0);
            return NULL;
      }

      return (address);
}
#endif


#ifndef ISC_REMAP_FILE_DEFINED
bool SharedMemoryBase::remapFile(Arg::StatusVector& statusVector, ULONG, bool)
{
/**************************************
 *
 *    I S C _ r e m a p _ f i l e         ( G E N E R I C )
 *
 **************************************
 *
 * Functional description
 *    Try to re-map a given file.
 *
 **************************************/

      statusVector << Arg::Gds(isc_unavailable) <<
                              Arg::Gds(isc_random) << "SharedMemory::remapFile";

      return NULL;
}
#endif


#ifdef UNIX
static TLS_DECLARE(sigjmp_buf*, sigjmp_ptr);

void ISC_sync_signals_set(void* arg)
{
/**************************************
 *
 *    I S C _ s y n c _ s i g n a l s _ s e t ( U N I X )
 *
 **************************************
 *
 * Functional description
 *    Set all the synchronous signals for a particular thread
 *
 **************************************/
      sigjmp_buf* const sigenv = static_cast<sigjmp_buf*>(arg);
      TLS_SET(sigjmp_ptr, sigenv);

      sigset(SIGILL, longjmp_sig_handler);
      sigset(SIGFPE, longjmp_sig_handler);
      sigset(SIGBUS, longjmp_sig_handler);
      sigset(SIGSEGV, longjmp_sig_handler);
}


void ISC_sync_signals_reset()
{
/**************************************
 *
 *    I S C _ s y n c _ s i g n a l s _ r e s e t ( U N I X )
 *
 **************************************
 *
 * Functional description
 *    Reset all the synchronous signals for a particular thread
 * to default.
 *
 **************************************/

      sigset(SIGILL, SIG_DFL);
      sigset(SIGFPE, SIG_DFL);
      sigset(SIGBUS, SIG_DFL);
      sigset(SIGSEGV, SIG_DFL);
}
#endif // UNIX

#ifdef UNIX
void SharedMemoryBase::unmapFile(Arg::StatusVector& statusVector)
{
/**************************************
 *
 *    I S C _ u n m a p _ f i l e         ( U N I X - m m a p )
 *
 **************************************
 *
 * Functional description
 *    Unmap a given file.
 *
 **************************************/
#ifdef USE_SYS5SEMAPHORE
      // Lock init file.
      FileLock initLock(statusVector, fd_init, FileLock::OPENED);
      if (!initLock.exclusive())
      {
            iscLogStatus("ISC_unmap_file failed to lock init file", statusVector.value());
      }
      else
      {
            SharedFile* sf = SharedFile::locate(getHeader());

            FileLock lock(statusVector, sh_mem_handle);
            lock.setLevel(FileLock::LCK_SHARED);
            semTable->cleanup(sf->getNum(), lock.tryExclusive());
            SharedFile::remove(getHeader());
      }
      --sharedCount;
#endif

#if defined(HAVE_OBJECT_MAP) && (!defined(USE_SYS5SEMAPHORE))
      unmapObject(statusVector, (UCHAR**) &sh_mem_mutex, sizeof(mtx));
#endif

      munmap((char *) getHeader(), sh_mem_length_mapped);
      setHeader(NULL);
      close(sh_mem_handle);
}
#endif

#ifdef WIN_NT
void SharedMemoryBase::unmapFile(Arg::StatusVector& statusVector)
{
/**************************************
 *
 *    I S C _ u n m a p _ f i l e         ( W I N _ N T )
 *
 **************************************
 *
 * Functional description
 *    Detach from the shared memory.
 *
 **************************************/

      CloseHandle(sh_mem_interest);
      if (!UnmapViewOfFile(getHeader()))
      {
            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;

      setHeader(NULL);
}
#endif


static void error(Arg::StatusVector& statusVector, const TEXT* string, ISC_STATUS status)
{
/**************************************
 *
 *    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();
}


#ifdef UNIX

#ifdef USE_SYS5SEMAPHORE

static SLONG create_semaphores(Arg::StatusVector& statusVector, SLONG key, int semaphores)
{
/**************************************
 *
 *    c r e a t e _ s e m a p h o r e s         ( U N I X )
 *
 **************************************
 *
 * Functional description
 *    Create or find a block of semaphores.
 *
 **************************************/
      while (true)
      {
            // Try to open existing semaphore set
            SLONG semid = semget(key, 0, 0);
            if (semid == -1)
            {
                  if (errno != ENOENT)
                  {
                        error(statusVector, "semget", errno);
                        return -1;
                  }
            }
            else
            {
                  union semun arg;
                  semid_ds buf;
                  arg.buf = &buf;
                  // Get number of semaphores in opened set
                  if (semctl(semid, 0, IPC_STAT, arg) == -1)
                  {
                        error(statusVector, "semctl", errno);
                        return -1;
                  }
                  if ((int) buf.sem_nsems >= semaphores)
                        return semid;
                  // Number of semaphores in existing set is too small. Discard it.
                  if (semctl(semid, 0, IPC_RMID) == -1)
                  {
                        error(statusVector, "semctl", errno);
                        return -1;
                  }
            }

            // 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
                  char secDb[MAXPATHLEN];
                  Auth::SecurityDatabase::getPath(secDb);
                  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;
            }

            if (errno != EEXIST)
            {
                  error(statusVector, "semget", errno);
                  return -1;
            }
      }
}

#endif // USE_SYS5SEMAPHORE

void longjmp_sig_handler(int sig_num)
{
/**************************************
 *
 *    l o n g j m p _ s i g _ h a n d l e r
 *
 **************************************
 *
 * Functional description
 *    The generic signal handler for all signals in a thread.
 *
 **************************************/

      siglongjmp(*TLS_GET(sigjmp_ptr), sig_num);
}

#endif // UNIX


#ifdef WIN_NT
static bool make_object_name(TEXT* buffer, size_t bufsize,
                                           const TEXT* object_name,
                                           const TEXT* object_type)
{
/**************************************
 *
 *    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 "_".
 *
 **************************************/
      char hostname[64];
      const int rc = snprintf(buffer, bufsize, object_name, ISC_get_host(hostname, sizeof(hostname)));
      if (size_t(rc) == bufsize || rc <= 0)
      {
            SetLastError(ERROR_FILENAME_EXCED_RANGE);
            return false;
      }

      char& limit = buffer[bufsize - 1];
      limit = 0;

      char* p;
      char c;
      for (p = buffer; c = *p; p++)
      {
            if (c == '/' || c == '\\' || c == ':')
                  *p = '_';
      }

      // 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;
      }

      strcpy(p, object_type);

      // hvlad: windows file systems use case-insensitive file names
      // while kernel objects such as events use case-sensitive names.
      // Since we use root directory as part of kernel objects names
      // we must use lower (or upper) register for object name to avoid
      // misunderstanding between processes
      strlwr(buffer);

      // 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;
}
#endif // WIN_NT

void SharedMemoryBase::mutexLock()
{
      int state = ISC_mutex_lock(sh_mem_mutex);
      if (state != 0)
      {
            mutexBug(state, "ISC_mutex_lock");
      }
}

bool SharedMemoryBase::mutexLockCond()
{
      return ISC_mutex_lock_cond(sh_mem_mutex) == 0;
}

void SharedMemoryBase::mutexUnlock()
{
      int state = ISC_mutex_unlock(sh_mem_mutex);
      if (state != 0)
      {
            mutexBug(state, "ISC_mutex_unlock");
      }
}

SharedMemoryBase::SharedMemoryBase()
  :   sh_mem_mutex(0), sh_mem_length_mapped(0),
#ifdef WIN_NT
      sh_mem_handle(0), sh_mem_object(0), sh_mem_interest(0), sh_mem_hdr_object(0),
      sh_mem_hdr_address(0)
#else
      sh_mem_handle(-1)
#endif
{
      sh_mem_name[0] = '\0';
}

SharedMemoryBase::~SharedMemoryBase()
{
}

void SharedMemoryBase::logError(const char* text, const Arg::StatusVector& status)
{
      iscLogStatus(text, status.value());
}

Generated by  Doxygen 1.6.0   Back to index