Generic_Window_Manager/reference.c

275 lines
6.5 KiB
C

/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT
* Copyright 1989 Massachusetts Institute of Technology
*/
/******************************************************\
* *
* reference.c: *
* reference count management and other storage issues *
* *
\******************************************************/
#include "EXTERN.h"
#include "wool.h"
/*
* The memory management of WOOL is implemented via a differed reference
* count. That, each time an object's reference count attains 0, it is put in
* the zrt, which is polled at regular intervals
*/
/************************************\
* *
* Zero_reference table module (zrt) *
* *
\************************************/
/*
* The zrt (Zero Reference Table) global structure is used to mark ALL wobs
* that have at any moment be of REF 0, that is either being created or via
* decrease_reference. Then you can call zrt_gc at strategic moments, (ie in
* no enclosing WOOL function) to free all the zero-referenced objects in the
* zrt.
*/
#ifdef STATS
//Er... this is an old-style function definition, right? So why does it have two types?
//WOOL_OBJECT
void zrtstats(void)
{
wool_printf("Zero-reference-table has %d", zrt_size);
wool_printf("/%d slots\n", zrt_limit);
}
#endif /* STATS */
void zrt_init(void)
{
zrt_size = 0;
zrt_limit = 63; /* pow(2,n)/4 -1 */
zrt = (WOOL_OBJECT *) Malloc(zrt_limit * sizeof(WOOL_OBJECT));
zrt_last = zrt;
}
/*
* disposes really of objects stacked in zrt. Be warned that a WOOL_free might
* trigger zrt_put during the zrt_gc !
*/
static int WlZrtInGc = 0;
void zrt_gc(int from)
{
WOOL_OBJECT *zrt_from = zrt + from;
WlZrtInGc = 1;
while (zrt_last > zrt_from) {
zrt_last--, zrt_size--;
if (REF(*zrt_last)) { /* ok, graduate to normal object */
(*zrt_last) -> reference_count |= 1;
} else { /* free it */
WOOL_send(WOOL_free, *zrt_last, (*zrt_last));
}
}
WlZrtInGc = 0;
}
/*
* Never call zrt_put if obj was already in it (sould not happen)
*/
WOOL_OBJECT zrt_put(WOOL_OBJECT obj)
{
WOOL_OBJECT *old_zrt;
#ifdef DEBUG
must_not_be_in_zrt(obj);
#endif /* DEBUG */
if (WlZrtInGc) {
WOOL_send(WOOL_free, obj, (obj));
} else {
if(zrt_size == zrt_limit) {
zrt_limit = (zrt_limit + 1) * 2 -1;
old_zrt = zrt;
zrt = (WOOL_OBJECT *) Realloc(zrt, zrt_limit *
sizeof(WOOL_OBJECT));
zrt_last = zrt + (zrt_last - old_zrt);
}
zrt_size ++;
obj -> reference_count = 0;
return *zrt_last++ = obj;
}
//I don't think we're supposed to reach here...
return NIL;
}
/* when an object is physically replaced by another, update its entry
* in the zrt
*/
void zrt_replace_element(WOOL_OBJECT old, WOOL_OBJECT new)
{
WOOL_OBJECT *zrt_ptr = zrt;
while (zrt_ptr < zrt_last) {
if (*zrt_ptr == old) {
*zrt_ptr = new;
return;
}
zrt_ptr++;
}
#ifdef DEBUG
wool_error("replaced object 0x%x was not in zrt!", old);
#endif /* DEBUG */
}
#ifdef DEBUG
/* checks that the element is not in fact already in the zrt...
*/
void must_not_be_in_zrt(WOOL_OBJECT obj)
{
WOOL_OBJECT *zrt_ptr = zrt;
while (zrt_ptr < zrt_last) {
if (*zrt_ptr == obj) {
wool_printf("at zrt[%d]", zrt_last - zrt);
wool_printf(" and zrt[%d], type: ", zrt_ptr - zrt);
wool_print(wool_type(obj));
wool_puts(", obj: ");
wool_print(obj);
wool_newline();
wool_error("object 0x%x was already in zrt!", obj);
}
zrt_ptr++;
}
}
#endif /* DEBUG */
/***********************\
* *
* reference management *
* *
\***********************/
/* increase_reference is a macro (REF(x)++) */
#ifdef DEBUG /* macro otherwise */
void increase_reference(WOOL_OBJECT obj) /* obj may be UNDEFINED */
{
REF(obj) += 2;
}
void decrease_reference(WOOL_OBJECT obj) /* obj may be UNDEFINED */
{
if (obj) {
if (((obj -> reference_count) -= 2) == 1)
zrt_put(obj);
else if (obj -> reference_count < 0) {
wool_print(obj);
wool_error(": reference_count became %d", obj ->
reference_count);
}
}
}
void decrease_reference_non_null(WOOL_OBJECT obj) /* obj must be non-nil */
{
if (((obj -> reference_count) -= 2) == 1)
zrt_put(obj);
else if (obj -> reference_count < 0) {
wool_print(obj);
wool_error(": reference_count became %d", obj ->
reference_count);
}
}
#endif /* DEBUG */
/*
* decrease_reference_in_list:
* decrease reference count of all the elements of the list.
* but doesn't free the list.
*/
void decrease_reference_in_list(int count, WOOL_OBJECT *list)
{
WOOL_OBJECT *last = list + count;
while (list < last){
decrease_reference(*list);
list++;
}
}
/*
* duplicate an array of objects, increasing the reference count,
* and mallocing
*/
void duplicate_n_objects(WOOL_OBJECT *source, WOOL_OBJECT **dest, int n) /* source is the array, dest is a POINTER to the array, n is how many to copy */
{
WOOL_OBJECT *p = source, *q, *last = source + n;
q = *dest = (WOOL_OBJECT *) Malloc(sizeof(WOOL_OBJECT) * n);
while (p < last)
increase_reference(*q++ = *p++);
}
/*
* duplicate an array of objects, increasing the reference count,
* without mallocing (dest already points to an malloced aera)
*/
void copy_n_objects(WOOL_OBJECT *source, WOOL_OBJECT *dest, int n) /* source is the array */ /* dest is the array */ /* how many to copy */
{
WOOL_OBJECT *p = source, *q = dest, *last = source + n;
while (p < last)
increase_reference(*q++ = *p++);
}
/************************************\
* *
* Delayed Free table module (dft) *
* *
\************************************/
/* this table holds all memory chunks that should be freed only when at the
* top-level
*/
#define INITIAL_DFT_SIZE 31 /* pow(2,n)/4 - 1 */
/* This table holds memory chunks that are to be freed at the top-level
*/
void dft_init(void)
{
dft = (char **) Malloc(INITIAL_DFT_SIZE * sizeof(char *));
dft_last = dft;
dft_last_allocated = dft + INITIAL_DFT_SIZE;
}
/* dft_gc disposes really of memory stacked in dft. Defined as a macro
* while (dft_last > dft) Free(*(--dft_last)) in wool.h
*/
/* put in dft for later freeing
*/
void DelayedFree(char *ptr)
{
ASSERT(ptr != NULL);
if(dft_last == dft_last_allocated) {
char **old_dft;
int size = dft_last - dft, old_size = size;
size = (size + 1) * 2 -1;
old_dft = dft;
dft = (char **) Realloc(dft, size * sizeof(char *));
dft_last = dft + old_size;
dft_last_allocated = dft + size;
}
*dft_last++ = ptr;
}