8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-25 00:43:03 +01:00
firebird-mirror/src/jrd/inuse.cpp
alexpeshkoff 1591a54e5e Thread cleanup:
1. Added macros to declare thread entrypoints
2. THD_mutex_* functions use Firebird::Mutex
3. Thread local storage use fb_tls.h
2004-06-08 13:41:08 +00:00

249 lines
5.7 KiB
C++

/*
* PROGRAM: JRD Access Method
* MODULE: inuse.cpp
* DESCRIPTION: Keep track of objects that are in use
*
* 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): ______________________________________.
*/
#include "firebird.h"
#include "../jrd/common.h"
#include <stdio.h>
#include "../jrd/jrd.h"
#include "../jrd/gds_proto.h"
#include "../jrd/inuse_proto.h"
#include "../jrd/thd.h"
static void cleanup(void *);
static void init(void);
static IUO free_list = NULL;
static MUTX_T inuse_mutex[1];
static bool initialized = false;
bool INUSE_cleanup(IUO inuse, void (*cleanup_routine) ())
{
/**************************************
*
* I N U S E _ c l e a n u p
*
**************************************
*
* Functional description
* Cleanup an in-use structure. If any
* objects are found to be non-NULL,
* call the cleanup routine. Return true
* if there was something to do.
*
**************************************/
bool needed_cleaning = false;
IUO secondary_inuse = inuse->iuo_next;
do {
void** ptr = inuse->iuo_object;
for (const void* const* const end = ptr + inuse->iuo_in_use_count;
ptr < end; ptr++)
{
if (*ptr) {
reinterpret_cast <
void (*) (void *) >(*cleanup_routine) (*ptr);
needed_cleaning = true;
}
}
inuse->iuo_in_use_count = 0;
} while (inuse = inuse->iuo_next);
if (secondary_inuse) {
IUO* secondary_end_ptr = &secondary_inuse->iuo_next;
while (*secondary_end_ptr)
secondary_end_ptr = &(*secondary_end_ptr)->iuo_next;
THD_MUTEX_LOCK(inuse_mutex);
*secondary_end_ptr = free_list;
free_list = secondary_inuse;
THD_MUTEX_UNLOCK(inuse_mutex);
}
return needed_cleaning;
}
void INUSE_clear(IUO inuse)
{
/**************************************
*
* I N U S E _ c l e a r
*
**************************************
*
* Functional description
* Initialize an in-use block.
*
**************************************/
if (!initialized)
init();
inuse->iuo_in_use_count = 0;
inuse->iuo_next = NULL;
}
bool INUSE_insert(IUO inuse, void *new_object, bool dup_flag)
{
/**************************************
*
* I N U S E _ i n s e r t
*
**************************************
*
* Functional description
* Insert an object into an in-use structure.
* If dup_flag is true, then duplicate entries
* are permitted. If it is false, then a
* duplicate entry will not be inserted.
* Return true if the object was inserted.
*
**************************************/
// "end" moves backwards in this loop.
void** ptr = inuse->iuo_object;
for (const void* const* end = ptr + inuse->iuo_in_use_count;
ptr < end; ptr++)
{
if (!*ptr) {
if (!dup_flag)
while (ptr < --end)
if (*end == new_object)
return false;
*ptr = new_object;
return true;
}
else if (!dup_flag && *ptr == new_object)
return false;
}
if (inuse->iuo_in_use_count >= FB_NELEM(inuse->iuo_object)) {
#ifdef DEV_BUILD
gds__log("in-use block overflow. secondary block allocated.");
#endif
THD_MUTEX_LOCK(inuse_mutex);
IUO new_inuse = free_list;
if (new_inuse) {
free_list = new_inuse->iuo_next;
THD_MUTEX_UNLOCK(inuse_mutex);
}
else {
THD_MUTEX_UNLOCK(inuse_mutex);
new_inuse = (IUO) gds__alloc((SLONG) sizeof(struct iuo));
/* FREE: at process exit, by cleanup handler cleanup() in this module */
if (!new_inuse) { /* NOMEM: */
DEV_REPORT("INUSE_insert: out of memory");
return false; /* error handling too difficult */
}
}
INUSE_clear(new_inuse);
inuse->iuo_next = new_inuse;
inuse = new_inuse;
}
inuse->iuo_object[inuse->iuo_in_use_count++] = new_object;
return true;
}
bool INUSE_remove(IUO inuse, void* old_object, bool dup_flag)
{
/**************************************
*
* I N U S E _ r e m o v e
*
**************************************
*
* Functional description
* Remove an object from an in-use structure.
* If dup_flag is true, remove every occurrence
* of the object. Otherwise, only remove the
* first. Return true if an object was removed.
*
**************************************/
bool removed = false;
do {
// "end" moves backwards here
void** ptr = inuse->iuo_object;
for (const void* const* end = ptr + inuse->iuo_in_use_count;
ptr < end; ptr++)
{
if (*ptr == old_object) {
*ptr = NULL;
if (ptr + 1 == end)
while (!*(--end) && --inuse->iuo_in_use_count);
if (!dup_flag)
return true;
removed = true;
}
}
} while (inuse = inuse->iuo_next);
return removed;
}
static void cleanup(void *arg)
{
/**************************************
*
* c l e a n u p
*
**************************************
*
* Functional description
*
**************************************/
while (free_list) {
IUO iuo = free_list;
free_list = iuo->iuo_next;
gds__free(iuo);
}
initialized = false;
}
static void init(void)
{
/**************************************
*
* i n i t
*
**************************************
*
* Functional description
*
**************************************/
if (!initialized) {
THD_INIT;
THD_GLOBAL_MUTEX_LOCK;
if (!initialized) {
gds__register_cleanup(cleanup, 0);
initialized = true;
}
THD_GLOBAL_MUTEX_UNLOCK;
}
}