2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Access Method
|
2004-02-20 07:43:27 +01:00
|
|
|
* MODULE: inuse.cpp
|
2001-05-23 15:26:42 +02:00
|
|
|
* 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): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
2001-07-29 19:42:23 +02:00
|
|
|
#include "firebird.h"
|
2004-03-22 12:38:23 +01:00
|
|
|
#include "../jrd/common.h"
|
2004-04-29 00:43:34 +02:00
|
|
|
#include <stdio.h>
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/jrd.h"
|
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
#include "../jrd/inuse_proto.h"
|
2004-06-08 15:41:08 +02:00
|
|
|
#include "../jrd/thd.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
static void cleanup(void *);
|
|
|
|
static void init(void);
|
|
|
|
|
|
|
|
static IUO free_list = NULL;
|
2007-06-06 14:37:24 +02:00
|
|
|
static Firebird::Mutex inuse_mutex;
|
2004-02-20 07:43:27 +01:00
|
|
|
static bool initialized = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2006-02-23 06:08:26 +01:00
|
|
|
bool INUSE_cleanup(IUO inuse, FPTR_VOID_PTR cleanup_routine)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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,
|
2004-02-20 07:43:27 +01:00
|
|
|
* call the cleanup routine. Return true
|
2001-05-23 15:26:42 +02:00
|
|
|
* if there was something to do.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-20 07:43:27 +01:00
|
|
|
bool needed_cleaning = false;
|
|
|
|
IUO secondary_inuse = inuse->iuo_next;
|
2001-05-23 15:26:42 +02:00
|
|
|
do {
|
2004-02-20 07:43:27 +01:00
|
|
|
void** ptr = inuse->iuo_object;
|
|
|
|
for (const void* const* const end = ptr + inuse->iuo_in_use_count;
|
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*ptr) {
|
2006-05-01 06:12:30 +02:00
|
|
|
// dimitr: this assert is put temporarily in order to track
|
|
|
|
// mutexes that could be left acquired when we leave
|
|
|
|
// the JRD context
|
|
|
|
fb_assert(false);
|
2006-02-23 06:08:26 +01:00
|
|
|
(*cleanup_routine) (*ptr);
|
2004-02-20 07:43:27 +01:00
|
|
|
needed_cleaning = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
inuse->iuo_in_use_count = 0;
|
|
|
|
} while (inuse = inuse->iuo_next);
|
|
|
|
|
|
|
|
if (secondary_inuse) {
|
2004-02-20 07:43:27 +01:00
|
|
|
IUO* secondary_end_ptr = &secondary_inuse->iuo_next;
|
|
|
|
while (*secondary_end_ptr)
|
2001-05-23 15:26:42 +02:00
|
|
|
secondary_end_ptr = &(*secondary_end_ptr)->iuo_next;
|
2007-06-06 14:37:24 +02:00
|
|
|
inuse_mutex.enter();
|
2001-05-23 15:26:42 +02:00
|
|
|
*secondary_end_ptr = free_list;
|
|
|
|
free_list = secondary_inuse;
|
2007-06-06 14:37:24 +02:00
|
|
|
inuse_mutex.leave();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
bool INUSE_insert(IUO inuse, void *new_object, bool dup_flag)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* I N U S E _ i n s e r t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Insert an object into an in-use structure.
|
2004-02-20 07:43:27 +01:00
|
|
|
* If dup_flag is true, then duplicate entries
|
|
|
|
* are permitted. If it is false, then a
|
2001-05-23 15:26:42 +02:00
|
|
|
* duplicate entry will not be inserted.
|
2004-02-20 07:43:27 +01:00
|
|
|
* Return true if the object was inserted.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-20 07:43:27 +01:00
|
|
|
// "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++)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!*ptr) {
|
|
|
|
if (!dup_flag)
|
|
|
|
while (ptr < --end)
|
|
|
|
if (*end == new_object)
|
2004-02-20 07:43:27 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
*ptr = new_object;
|
2004-02-20 07:43:27 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else if (!dup_flag && *ptr == new_object)
|
2004-02-20 07:43:27 +01:00
|
|
|
return false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-12-02 10:45:52 +01:00
|
|
|
if (inuse->iuo_in_use_count >= FB_NELEM(inuse->iuo_object)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef DEV_BUILD
|
|
|
|
gds__log("in-use block overflow. secondary block allocated.");
|
|
|
|
#endif
|
2007-06-06 14:37:24 +02:00
|
|
|
inuse_mutex.enter();
|
2004-02-20 07:43:27 +01:00
|
|
|
IUO new_inuse = free_list;
|
|
|
|
if (new_inuse) {
|
2001-05-23 15:26:42 +02:00
|
|
|
free_list = new_inuse->iuo_next;
|
2007-06-06 14:37:24 +02:00
|
|
|
inuse_mutex.leave();
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else {
|
2007-06-06 14:37:24 +02:00
|
|
|
inuse_mutex.leave();
|
2001-05-23 15:26:42 +02:00
|
|
|
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");
|
2004-02-20 07:43:27 +01:00
|
|
|
return false; /* error handling too difficult */
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
INUSE_clear(new_inuse);
|
|
|
|
inuse->iuo_next = new_inuse;
|
|
|
|
inuse = new_inuse;
|
|
|
|
}
|
|
|
|
|
|
|
|
inuse->iuo_object[inuse->iuo_in_use_count++] = new_object;
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
bool INUSE_remove(IUO inuse, void* old_object, bool dup_flag)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* I N U S E _ r e m o v e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Remove an object from an in-use structure.
|
2004-02-20 07:43:27 +01:00
|
|
|
* If dup_flag is true, remove every occurrence
|
2001-05-23 15:26:42 +02:00
|
|
|
* of the object. Otherwise, only remove the
|
2004-02-20 07:43:27 +01:00
|
|
|
* first. Return true if an object was removed.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-20 07:43:27 +01:00
|
|
|
bool removed = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
do {
|
2004-02-20 07:43:27 +01:00
|
|
|
// "end" moves backwards here
|
|
|
|
void** ptr = inuse->iuo_object;
|
|
|
|
for (const void* const* end = ptr + inuse->iuo_in_use_count;
|
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*ptr == old_object) {
|
|
|
|
*ptr = NULL;
|
|
|
|
if (ptr + 1 == end)
|
|
|
|
while (!*(--end) && --inuse->iuo_in_use_count);
|
|
|
|
if (!dup_flag)
|
2004-02-20 07:43:27 +01:00
|
|
|
return true;
|
|
|
|
removed = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2004-02-20 07:43:27 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
} while (inuse = inuse->iuo_next);
|
|
|
|
|
|
|
|
return removed;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void cleanup(void *arg)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c l e a n u p
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
while (free_list) {
|
2004-02-20 07:43:27 +01:00
|
|
|
IUO iuo = free_list;
|
2001-05-23 15:26:42 +02:00
|
|
|
free_list = iuo->iuo_next;
|
|
|
|
gds__free(iuo);
|
|
|
|
}
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
initialized = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void init(void)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* i n i t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
if (!initialized) {
|
|
|
|
THD_GLOBAL_MUTEX_LOCK;
|
|
|
|
if (!initialized) {
|
|
|
|
gds__register_cleanup(cleanup, 0);
|
2004-02-20 07:43:27 +01:00
|
|
|
initialized = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
THD_GLOBAL_MUTEX_UNLOCK;
|
|
|
|
}
|
|
|
|
}
|