8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-26 08:03:03 +01:00
firebird-mirror/src/jrd/isc_sync_win32.cpp
dimitr c161723107 Corrected the exception handling logic:
- check asynchronous (hardware) exceptions first
  - proper memory management
2002-09-05 09:00:04 +00:00

934 lines
23 KiB
C++

/*
* PROGRAM: JRD Access Method
* MODULE: isc_sync.c
* DESCRIPTION: General purpose but non-user routines. Win32 specific.
*
* 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): ______________________________________.
*/
#ifdef SHLIB_DEFS
#define LOCAL_SHLIB_DEFS
#endif
#include "firebird.h"
#include "../jrd/ib_stdio.h"
#include <stdlib.h>
#include <string.h>
#include <process.h>
#include <signal.h>
#include <windows.h>
#include "../jrd/time.h"
#include "../jrd/common.h"
#include "gen/codes.h"
#include "../jrd/isc.h"
#include "../jrd/err_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/isc_proto.h"
#include "../jrd/isc_i_proto.h"
#include "../jrd/isc_s_proto.h"
#include "../jrd/file_params.h"
#include "../jrd/jrd.h"
#include "../jrd/sch_proto.h"
#include "../jrd/thd_proto.h"
extern "C" {
static int process_id;
static void error(STATUS *, TEXT *, STATUS);
static void make_object_name( char* buffer,
const char* object_name,
const char* object_type);
#ifdef SHLIB_DEFS
#define sprintf (*_libgds_sprintf)
#define strlen (*_libgds_strlen)
#define strcpy (*_libgds_strcpy)
#define errno (*_libgds_errno)
#define open (*_libgds_open)
#define close (*_libgds_close)
#pragma FB_COMPILER_MACRO("Warning! Possibly unsafe new declaration of errno.")
// e.g. MS C runtime library defines errno as a macro (to get the
// real errno in a thread-safe fashion).
extern int errno;
#endif // SHLIB_DEFS
#ifdef SIG_RESTART
//
// Return a flag that indicats whether or not to restart an interrupted
// system call.
//
BOOLEAN ISC_check_restart (void)
{
return TRUE;
}
#endif /* SIG_RESTART */
//
// If a wait would block, return TRUE.
//
int ISC_event_blocked(USHORT count, EVENT* events, SLONG* values)
{
for (; count > 0; --count, ++events, ++values) {
EVENT pEvent = *events;
if (pEvent->event_shared) {
pEvent = pEvent->event_shared;
}
if (pEvent->event_count >= *values) {
return FALSE;
}
}
return TRUE;
}
//
// 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.
//
SLONG DLL_EXPORT ISC_event_clear(EVENT event)
{
ResetEvent ((HANDLE) event->event_handle);
EVENT pEvent = event;
if (pEvent->event_shared) {
pEvent = pEvent->event_shared;
}
return pEvent->event_count + 1;
}
//
// Discard an event object.
//
void ISC_event_fini(EVENT event)
{
CloseHandle ((HANDLE) event->event_handle);
}
//
// Prepare an event object for use.
//
int DLL_EXPORT ISC_event_init(EVENT event, int type, int semnum)
{
event->event_pid = process_id = getpid();
event->event_count = 0;
event->event_type = type;
event->event_shared = NULL;
event->event_handle = ISC_make_signal(TRUE, TRUE, process_id, type);
return (event->event_handle) ? TRUE : FALSE;
}
//
// Prepare an event object for use.
//
int ISC_event_init_shared (
EVENT lcl_event,
int type,
TEXT *name,
EVENT shr_event,
USHORT init_flag)
{
TEXT event_name [MAXPATHLEN], type_name [16];
lcl_event->event_pid = process_id = getpid();
lcl_event->event_count = 0;
lcl_event->event_type = type;
lcl_event->event_shared = shr_event;
sprintf (type_name, "_event%d", type);
make_object_name (event_name, name, type_name);
if (!(lcl_event->event_handle = CreateEvent (ISC_get_security_desc(), TRUE, FALSE, event_name)))
return FALSE;
if (init_flag)
{
shr_event->event_pid = 0;
shr_event->event_count = 0;
shr_event->event_type = type;
shr_event->event_handle = NULL;
shr_event->event_shared = NULL;
}
return TRUE;
}
//
// Post an event to wake somebody else up.
//
int DLL_EXPORT ISC_event_post(EVENT event)
{
if (!event->event_shared)
++event->event_count;
else
++event->event_shared->event_count;
if (event->event_pid != process_id) {
ISC_kill (event->event_pid, event->event_type, event->event_handle);
} else {
SetEvent ((HANDLE) event->event_handle);
}
return 0;
}
//
// Wait on an event.
//
int DLL_EXPORT ISC_event_wait (
SSHORT count,
EVENT *events,
SLONG *values,
SLONG micro_seconds,
void (*timeout_handler)(),
void *handler_arg)
{
EVENT* ptr;
EVENT* end;
HANDLE handles[16];
HANDLE* handle_ptr;
/* If we're not blocked, the rest is a gross waste of time */
if (!ISC_event_blocked (count, events, values)) {
return 0;
}
for (ptr = events, end = events + count, handle_ptr = handles; ptr < end;) {
*handle_ptr++ = (*ptr++)->event_handle;
}
/* Go into wait loop */
DWORD timeout = (micro_seconds > 0) ? micro_seconds / 1000 : INFINITE;
for (;;)
{
if (!ISC_event_blocked (count, events, values)) {
return 0;
}
const DWORD status =
WaitForMultipleObjects((DWORD) count, handles, TRUE, timeout);
if (!((status >= WAIT_OBJECT_0) && (status < WAIT_OBJECT_0 + count))) {
return status;
}
}
}
#ifdef SUPERSERVER
/**************************************
*
* 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 ISC_exception_post(ULONG except_code, TEXT* err_msg)
{
ULONG result;
bool is_critical = true;
if (!SCH_thread_enter_check ())
{
THREAD_ENTER;
}
TDBB tdbb = GET_THREAD_DATA;
if (!err_msg)
{
err_msg = "";
}
TEXT *log_msg = (TEXT *) gds__alloc(strlen(err_msg) + 256);
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"
"\t\tresult 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:
ERR_post(isc_exception_stack_overflow, 0);
/* This will never be called, but to be safe it's here */
result = 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;
default:
/* If we've catched our own software exception,
continue rewinding the stack to properly handle it
and deliver an error information to the client side */
if (tdbb->tdbb_status_vector[0] == 1 && tdbb->tdbb_status_vector[1] > 0)
{
result = EXCEPTION_CONTINUE_SEARCH;
is_critical = false;
}
else
{
sprintf (log_msg, "%s An exception occurred that does\n"
"\t\tnot have a description. Exception number %X.\n"
"\tThis exception will cause the Firebird server\n"
"\tto terminate abnormally.", err_msg, except_code);
}
break;
}
gds__log(log_msg);
gds__free(log_msg);
if (is_critical)
{
exit(3);
}
else
{
return result;
}
}
#endif /* SUPERSERVER */
//
// Create or open a Windows/NT event.
// Use the signal number and process id
// in naming the object.
//
void* ISC_make_signal(
BOOLEAN create_flag,
BOOLEAN manual_reset,
int process_id,
int signal_number)
{
if (!signal_number) {
return CreateEvent (NULL, manual_reset, FALSE, NULL);
}
TEXT event_name [64];
sprintf(event_name, "_interbase_process%u_signal%d", process_id, signal_number);
HANDLE hEvent;
if (create_flag) {
hEvent = CreateEvent(ISC_get_security_desc(), manual_reset, FALSE, event_name);
} else {
hEvent = OpenEvent(EVENT_ALL_ACCESS, TRUE, event_name);
}
return hEvent;
}
//
// 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).
//
UCHAR * DLL_EXPORT ISC_map_file (
STATUS* status_vector,
TEXT* filename,
#if 1
// TMN: Parameter is in errors!
void (*init_routine)(void *, struct sh_mem *, int),
#else
// MUST of course match header.
FPTR_VOID init_routine,
#endif
void* init_arg,
SLONG length,
SH_MEM shmem_data)
{
TEXT expanded_filename [MAXPATHLEN], hostname [64], *p;
TEXT map_file [MAXPATHLEN];
HANDLE file_handle, event_handle;
int init_flag;
DWORD ret_event, fdw_create;
int retry_count = 0;
/* To maintain compatibility with the FAT file system we will truncate
the host name to 8 characters. Heaven help us if this creates
an ambiguity. */
/* retry to attach to mmapped file if the process initializing
* dies during initialization.
*/
retry:
retry_count++;
ISC_get_host (hostname, sizeof (hostname));
hostname [8] = 0;
sprintf (map_file, filename, hostname);
if (length < 0)
length = -length;
file_handle =
CreateFile( map_file,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (file_handle == INVALID_HANDLE_VALUE)
{
error(status_vector, "CreateFile", GetLastError());
return NULL;
}
/* Check if file already exists */
const bool file_exists = (GetLastError() == ERROR_ALREADY_EXISTS);
// Create an event that can be used to determine if someone has already
// initialized shared memory.
make_object_name (expanded_filename, filename, "_event");
#ifndef CHICAGO_FIXED
if (!ISC_is_WinNT())
event_handle = CreateMutex (ISC_get_security_desc(), TRUE, expanded_filename);
else
#endif
event_handle = CreateEvent (ISC_get_security_desc(), TRUE, FALSE, expanded_filename);
if (!event_handle)
{
#ifndef CHICAGO_FIXED
if (!ISC_is_WinNT())
error (status_vector, "CreateMutex", GetLastError());
else
#endif
error (status_vector, "CreateEvent", GetLastError());
CloseHandle(file_handle);
return NULL;
}
init_flag = (GetLastError() == ERROR_ALREADY_EXISTS) ? FALSE : TRUE;
if (init_flag && !init_routine)
{
CloseHandle (event_handle);
CloseHandle (file_handle);
*status_vector++ = gds_arg_gds;
*status_vector++ = gds_unavailable;
*status_vector++ = gds_arg_end;
return NULL;
}
if (length == 0)
{
/* Get and use the existing length of the shared segment */
if ((length = GetFileSize (file_handle, NULL)) == -1)
{
error (status_vector, "GetFileSize", GetLastError());
CloseHandle (event_handle);
CloseHandle (file_handle);
return NULL;
}
}
/* 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 */
#ifndef CHICAGO_FIXED
if (!ISC_is_WinNT())
{
ret_event = WaitForSingleObject (event_handle, 10000);
ReleaseMutex (event_handle);
}
else
#endif
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 (status_vector, "WaitForSingleObject", GetLastError());
return NULL;
}
goto retry;
}
}
if (init_flag && file_exists)
fdw_create = TRUNCATE_EXISTING | OPEN_ALWAYS;
else
fdw_create = OPEN_ALWAYS;
file_handle = CreateFile( map_file,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
fdw_create,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (file_handle == INVALID_HANDLE_VALUE)
{
CloseHandle (event_handle);
error (status_vector, "CreateFile", GetLastError());
return NULL;
}
// 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.
make_object_name (expanded_filename, filename, "_mapping");
HANDLE header_obj =
CreateFileMapping ((HANDLE) -1,
ISC_get_security_desc(),
PAGE_READWRITE,
0,
2 * sizeof (SLONG),
expanded_filename);
if (header_obj == NULL)
{
error (status_vector, "CreateFileMapping", GetLastError());
CloseHandle (event_handle);
CloseHandle (file_handle);
return NULL;
}
SLONG* header_address =
(SLONG*)MapViewOfFile (header_obj, FILE_MAP_WRITE, 0, 0, 0);
if (header_address == NULL)
{
error (status_vector, "CreateFileMapping", GetLastError());
CloseHandle (header_obj);
CloseHandle (event_handle);
CloseHandle (file_handle);
return NULL;
}
// 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. */
for (p = expanded_filename; *p; p++)
;
sprintf (p, "%d", header_address [1]);
HANDLE file_obj =
CreateFileMapping( file_handle,
ISC_get_security_desc(),
PAGE_READWRITE,
0,
length,
expanded_filename);
if (file_obj == NULL)
{
error (status_vector, "CreateFileMapping", GetLastError());
UnmapViewOfFile (header_address);
CloseHandle (header_obj);
CloseHandle (event_handle);
CloseHandle (file_handle);
return NULL;
}
UCHAR* address =
(UCHAR*)MapViewOfFile (file_obj, FILE_MAP_WRITE, 0, 0, 0);
if (address == NULL)
{
error (status_vector, "CreateFileMapping", GetLastError());
CloseHandle (file_obj);
UnmapViewOfFile (header_address);
CloseHandle (header_obj);
CloseHandle (event_handle);
CloseHandle (file_handle);
return NULL;
}
*p = 0;
shmem_data->sh_mem_address = address;
shmem_data->sh_mem_length_mapped = length;
shmem_data->sh_mem_handle = file_handle;
shmem_data->sh_mem_object = file_obj;
shmem_data->sh_mem_interest = event_handle;
shmem_data->sh_mem_hdr_object = header_obj;
shmem_data->sh_mem_hdr_address = header_address;
strcpy (shmem_data->sh_mem_name, expanded_filename);
if (init_routine) {
// Lie a bit to make it compile...
reinterpret_cast<void(*)(void*, sh_mem*,int)>(*init_routine) (init_arg, shmem_data, init_flag);
}
if (init_flag)
{
FlushViewOfFile (address, 0);
#ifndef CHICAGO_FIXED
if (!ISC_is_WinNT())
ReleaseMutex (event_handle);
else
#endif
SetEvent (event_handle);
if (SetFilePointer (shmem_data->sh_mem_handle, length, NULL, FILE_BEGIN) == 0xFFFFFFFF ||
!SetEndOfFile (shmem_data->sh_mem_handle) ||
!FlushViewOfFile (shmem_data->sh_mem_address, 0))
{
error (status_vector, "SetFilePointer", GetLastError());
return NULL;
}
}
return address;
}
//
// Initialize a mutex.
//
int DLL_EXPORT ISC_mutex_init(MTX mutex, TEXT* mutex_name)
{
char name_buffer[MAXPATHLEN];
make_object_name(name_buffer, mutex_name, "_mutex");
mutex->mtx_handle = CreateMutex(ISC_get_security_desc(), FALSE, name_buffer);
return mutex->mtx_handle ? 0 : 1;
}
//
// Sieze a mutex.
//
int DLL_EXPORT ISC_mutex_lock(MTX mutex)
{
const DWORD status = WaitForSingleObject(mutex->mtx_handle, INFINITE);
return (!status || status == WAIT_ABANDONED) ? 0 : 1;
}
//
// Conditionally sieze a mutex.
//
int DLL_EXPORT ISC_mutex_lock_cond(MTX mutex)
{
const DWORD status = WaitForSingleObject (mutex->mtx_handle, 0L);
return (!status || status == WAIT_ABANDONED) ? 0 : 1;
}
//
// Release a mutex.
//
int DLL_EXPORT ISC_mutex_unlock(MTX mutex)
{
return !ReleaseMutex(mutex->mtx_handle);
}
//
// Try to re-map a given file.
//
UCHAR * DLL_EXPORT ISC_remap_file (
STATUS* status_vector,
SH_MEM shmem_data,
SLONG new_length,
USHORT flag)
{
if (flag) {
if (SetFilePointer (shmem_data->sh_mem_handle, new_length, NULL, FILE_BEGIN) == 0xFFFFFFFF ||
!SetEndOfFile (shmem_data->sh_mem_handle) ||
!FlushViewOfFile (shmem_data->sh_mem_address, 0))
{
error (status_vector, "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;
while (1)
{
TEXT expanded_filename[MAXPATHLEN];
sprintf(expanded_filename,
"%s%d",
shmem_data->sh_mem_name,
shmem_data->sh_mem_hdr_address[1] + 1);
file_obj = CreateFileMapping( shmem_data->sh_mem_handle,
ISC_get_security_desc(),
PAGE_READWRITE,
0,
new_length,
expanded_filename);
if (!((GetLastError () == ERROR_ALREADY_EXISTS) && flag))
break;
CloseHandle (file_obj);
shmem_data->sh_mem_hdr_address [1] ++;
}
if (file_obj == NULL)
{
error (status_vector, "CreateFileMapping", GetLastError());
return NULL;
}
LPVOID address = MapViewOfFile(file_obj, FILE_MAP_WRITE, 0, 0, 0);
if (address == NULL)
{
error (status_vector, "CreateFileMapping", GetLastError());
CloseHandle (file_obj);
return NULL;
}
if (flag)
{
shmem_data->sh_mem_hdr_address [0] = new_length;
shmem_data->sh_mem_hdr_address [1]++;
}
UnmapViewOfFile(shmem_data->sh_mem_address);
CloseHandle(shmem_data->sh_mem_object);
shmem_data->sh_mem_address = reinterpret_cast<UCHAR*>(address);
shmem_data->sh_mem_length_mapped = new_length;
shmem_data->sh_mem_object = file_obj;
return reinterpret_cast<UCHAR*>(address);
}
//
// Detach from the shared memory. Depending upon the flag,
// get rid of the semaphore and/or get rid of shared memory.
//
void DLL_EXPORT ISC_unmap_file(
STATUS *status_vector,
SH_MEM shmem_data,
USHORT flag)
{
CloseHandle (shmem_data->sh_mem_interest);
CloseHandle ((HANDLE) shmem_data->sh_mem_mutex_arg);
UnmapViewOfFile (shmem_data->sh_mem_address);
CloseHandle (shmem_data->sh_mem_object);
if (flag & ISC_MEM_REMOVE) {
if (SetFilePointer (shmem_data->sh_mem_handle, 0, NULL, FILE_BEGIN) != 0xFFFFFFFF) {
SetEndOfFile (shmem_data->sh_mem_handle);
}
}
CloseHandle (shmem_data->sh_mem_handle);
UnmapViewOfFile(shmem_data->sh_mem_hdr_address);
CloseHandle (shmem_data->sh_mem_hdr_object);
}
//
// We've encountered an error, report it.
//
static void error(STATUS* status_vector, TEXT* string, STATUS status)
{
*status_vector++ = gds_arg_gds;
*status_vector++ = gds_sys_request;
*status_vector++ = gds_arg_string;
*status_vector++ = reinterpret_cast<STATUS>(string);
*status_vector++ = SYS_ARG;
*status_vector++ = status;
*status_vector++ = gds_arg_end;
}
//
// Create an object name from a name and type.
// Also replace the file separator with "_".
//
static void make_object_name( char* buffer,
const char* object_name,
const char* object_type)
{
char hostname[64];
char* p;
char c;
sprintf(buffer, object_name, ISC_get_host(hostname, sizeof(hostname)));
for (p = buffer; c = *p; p++) {
if (c == '/' || c == '\\' || c == ':') {
*p = '_';
}
}
strcpy(p, object_type);
}
} // extern "C"