Personal tools
You are here: Home Projects C++ Cfront releases Release 3.0.3 source libSC fs libsrc reg.c
Document Actions

reg.c

by Michael L Powell last modified 2007-01-26 03:24

Click here to get the file

Size 19.4 kB - File type text/plain

File contents

/*ident	"@(#)fs:libsrc/reg.c	3.1" */
/******************************************************************************
*
* C++ Standard Components, Release 3.0.
*
* Copyright (c) 1991, 1992 AT&T and Unix System Laboratories, Inc.
* Copyright (c) 1988, 1989, 1990 AT&T.  All Rights Reserved.
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T and Unix System
* Laboratories, Inc.  The copyright notice above does not evidence
* any actual or intended publication of such source code.
*
******************************************************************************/

/* Include fs.h to make sure the prototypes it contains match 
*  the definitions in this file.
*/
#include <fs.h>

#include "fslib.h"
#include <assert.h>
#include <stdlib.h>
#include <new.h>
#include <malloc.h>
#include <stdio.h>


/* THE CODE IN THIS FILE CANNOT (and currently does not) RELY ON STATIC 
*  CONSTRUCTORS HAVING ALREADY BEEN CALLED.  That is, ALL THE CODE IN 
*  THIS FILE MUST BE (and is, as it is currently written) READY TO EXECUTE 
*  UPON PROGRAM LOAD.  This is to enable the freestore manager to manage 
*  objects that are newed during static construction.
*/

/* Every newed object gets a number, in sequence.  
*  Counter is the number of the *next* object to be newed.
*/
static int counter = 0;

/* fs_descriptor_ATTLC for an object on the free store.
*/
class fs_descriptor_ATTLC {
public:
	// don't call program's operator new, it will confuse user
	void *operator new(size_t) { return malloc(sizeof(fs_descriptor_ATTLC)); }
	void operator delete(void *p) { if (p) free((char*)p); }

	const char *type;	// Type of object.
	long number;	// Number of objects.  
			//	Possible values: 
			//	-2: no idea
			//	-1: it's an array, but couldn't figure out how many
			//	>=0: that many
			//
	size_t size;	// Sizeof (single) object.
	const void *addr;	// Memory address of object.
	const char *file;	// File and line number newed on.
	int line;	//
	long onum;	// Object number.  Onums steadily increase and are never reused.
	int atuse;	// After registering, this is true if we registered at use of new; 
			// after unregistering, this is true if we unregistered at use of new.
	int watched;	// Is there a delete-watch on this object?
			//
	fs_descriptor_ATTLC *prev, *next;  // Previous and next fs_descriptor_ATTLC in implicit container of all fs_descriptor_ATTLCs.

	void print(FILE *f);
};

void fs_descriptor_ATTLC::print(FILE *f)
{
	fprintf(f, "#%d", onum);
	if (watched)
		fprintf(f, " (watched)");
	fprintf(f, ": %s", type);
	if (number == -1)  // it's an array, but don't know how many
		fprintf(f, "[]");
	else if (number > 1)
		fprintf(f, "[%d]", number);
	if (line >= 0)
		fprintf(f, ", newed on line `%s`%d", file, line);
	fprintf(f, " (size %d at %lx)", size, addr);
	if (number == -2)
		fprintf(f, ", alert!");
	fprintf(f, "\n");
}

/* First and last fs_descriptor_ATTLC in implicit container of all fs_descriptor_ATTLCs.
*/
static fs_descriptor_ATTLC *first = 0;
static fs_descriptor_ATTLC *last = 0;

/* Are all objects being delete-watched?
*  Is the freestore being new-watched?
*/
static int dwatch = 0;
static int nwatch = 0;


/* The mapping from freestore locations to fs_descriptor_ATTLCs is implemented
*  by the following functions:
*	_fs_insert_des_ATTLC
*	_fs_remove_des_ATTLC
*	_fs_get_des_ATTLC
*/

/* The variable regAndUnreg determines whether newed objects get registered
*  and deleted objects get deregistered.
*
*  Every object that's newed gets a fs_descriptor_ATTLC, and every object that's deleted
*  loses its fs_descriptor_ATTLC.  The exceptions are the objects newed by the freestore
*  manager itself.  Two reasons for not fs_descriptor_ATTLCing these objects: (1) the user 
*  doesn't want to see them, and (2) if we fs_descriptor_ATTLCed them, there'd be an 
*  infinite regression of fs_descriptor_ATTLCs.
*/

static int regAndUnreg = 1;

static int verbose = 1;
extern void fs_verbose()
{
	verbose = 1;
}
extern void fs_terse()
{
	verbose = 0;
}


/* The user is supposed to set a breakpoint on this function at the beginning of debugging.
*  The breakpoint will have to be reset whenever the program is reloaded into the debugger.
*/
extern void fs_break()
{
}

static void setDes(fs_descriptor_ATTLC *dp, int atuse, const char *file, int line, const char *type, 
	size_t size, const void *p, long onum, int watched, long number)
{
	dp->file = file;
	dp->line = line;
	dp->type = type;
	dp->size = size;
	dp->addr = p;
	dp->onum = onum;
	dp->watched = watched;
	dp->atuse = atuse;
	dp->number = number;
}

static void addToImplicitContainer(fs_descriptor_ATTLC *dp)
{
	dp->next = 0;
	dp->prev = last;
	if (first == 0)	first = dp;
	else		last->next = dp;
	last = dp;
}

static void delFromImplicitContainer(fs_descriptor_ATTLC *dp)
{
	if (dp->prev)	dp->prev->next = dp->next;
	else		first = dp->next;
	if (dp->next) 	dp->next->prev = dp->prev;
	else		last = dp->prev;
}


static void checkForSizeProblems(long defnumber, size_t defsize, long usenumber, size_t usesize)
{
	if (usenumber >= 0 /*&& usesize >= 0*/ && defsize != usesize * usenumber)
	{
		if (usenumber == 1)
		{
			fprintf(stderr, "freestore: Something appears very wrong to me.  The size of an object\n");
			fprintf(stderr, "just created doesn't match the size of its type.\n");
		}
		else
		{
			fprintf(stderr, "freestore: Something appears very wrong to me.  The size of an array\n");
			fprintf(stderr, "of objects just created doesn't match the size of its type times\n");
			fprintf(stderr, "the number of elements in the array.\n");
		}
		fs_break();
	}
	if (defnumber >= 0 && defnumber != usenumber)
	{
		fprintf(stderr, "freestore: Something appears very wrong to me.  The number of objects\n");
		fprintf(stderr, "just created doesn't match the number requested.\n");
		fs_break();
	}
}


/* The following function returns true iff it looks like we just a moment 
*  ago registered an object at the definition of operator new, and now 
*  we're trying to register it again at the corresponding use of new.  
*  dp is the fs_descriptor_ATTLC that was created at the definition registration.
*
*  The algorithm I use to decide this condition isn't perfect.  In fact,
*  no algorithm can be, since the following sequence of events is possible,
*  but not detectable:
*
*	1. Object O1 is newed, and registered at the definition of new.
*	2. O1 is not registered at the use of new.
*	3. O1 is deleted, but not unregistered (either at the use or the
*	   definition of delete).
*	4. Object O2 is newed, but not registered at the definition of 
*	   new.  Further, the memory location of O2 is the same as O1.
*	5. Object O2 is registered at the use of new.
*
* In this sequence of events, there is no way to tell that O1 and O2 are 
* different objects.  My algorithm, like all others, will think they're
* the same object, that is, that step 5 is simply the use-reg of the object
* that was def-reg'd in step 1.  
*/
static int useregOfSameObject(
	fs_descriptor_ATTLC *	dp, 
	int 		atuse, 
	size_t 		size, 
	long 		number, 
	const void *	p)
{
	/* This is how I test the condition, fallible though it may be.
	*/
	int cond = ((!dp->atuse && atuse) 	// if we were at a def, and now we're at a use,
		&& (dp->addr == p));		// and if the "two" objects are at the same location,
						// THEN it's high probability that we're now use-reg'ing 
						// the object we already def-reg'd.

	if (cond) 
		checkForSizeProblems(dp->number, dp->size, number, size);
	return cond;
}


static void checkForNBreak(fs_descriptor_ATTLC *)
{
	if (nwatch)
	{
		fprintf(stderr, "freestore: An object has been allocated, and is about to be initialized.\n");
		fs_break();
	}
}


static void do_registerConsultingfs_descriptor_ATTLC(fs_descriptor_ATTLC *dp, int atuse, const char *file, 
	int line, const char *type, size_t size, long number, const void *p)
{
	if (useregOfSameObject(dp, atuse, size, number, p))
	{
		/* remember that the type specified in the use of new should (and 
		* does) override the type specified in the definition of new, 
		* since we might have used an inherited definition of new.
		*/
		setDes(dp, atuse, file, line, type, size, p, dp->onum, dp->watched, number);
	}
	else
	{
//		if (dp->watched || dwatch || verbose)
		{
			fprintf(stderr, "freestore: Something is fishy.  You are about to construct\n");
			fprintf(stderr, "an object into the memory location that I believe object #%d\n", dp->onum);
			fprintf(stderr, "is currently occupying.  Either I didn't detect the deletion\n");
			fprintf(stderr, "of object #%d (which would happen only if both the use and\n", dp->onum);
			fprintf(stderr, "the def of the instance of operator delete which deleted \n");
			fprintf(stderr, "object #%d were not compiled with -fs), or you really did\n", dp->onum);
			fprintf(stderr, "forget to destroy object #%d.  I will assume the former.\n", dp->onum);
			fs_break();
		}

		/* to keep the container sorted by onum
		*/
		delFromImplicitContainer(dp);
		addToImplicitContainer(dp);

		setDes(dp, atuse, file, line, type, size, p, counter++, 0, number);
		checkForNBreak(dp);
	}
}


static void do_register(int atuse, const char *file, int line, const char *type, size_t size, long number, const void *p)
{
	fs_descriptor_ATTLC *dp;
	if ((dp = _fs_get_des_ATTLC(p)) != NOT_FOUND)
		do_registerConsultingfs_descriptor_ATTLC(dp, atuse, file, line, type, size, number, p);
	else
	{
		dp = new fs_descriptor_ATTLC;
		setDes(dp, atuse, file, line, type, size, p, counter++, 0, number);
		addToImplicitContainer(dp);
		_fs_insert_des_ATTLC(p, dp);
		checkForNBreak(dp);
	}
}


/* Registration and deregistration routines used by all instrumented 
*  uses and defs of all news and deletes (not just the default global ones above).
*/
extern void *_fs_register_ATTLC(int atuse, const char *file, int line, const char *type, size_t size, long number, const void *p)
{
	if (regAndUnreg)
	{
		regAndUnreg = 0;
		do_register(atuse, file, line, type, size, number, p);
		regAndUnreg = 1;
	}
	return (void*)p;
}


/* Check to see if we should break before deleting this object.
*/
static void checkForDBreak(fs_descriptor_ATTLC *dp)
{
	if (dp->watched || dwatch) 
	{
		fprintf(stderr, "freestore: Object #%d is about to be deleted.\n", dp->onum);
		fs_break();				
	}
}


static void do_unregister(int atuse, const void *p)
{	
	fs_descriptor_ATTLC *dp;
	if ((dp = _fs_remove_des_ATTLC(p)) != NOT_FOUND)
	{
		dp->atuse = atuse;
		checkForDBreak(dp);
		delFromImplicitContainer(dp);
		delete dp;
	}
	// else no fs_descriptor_ATTLC for this object.
/*
*	It's tough to tell if we are attempting a definition unregistration
*	of an object we just use unregistered.  E.g., the following sequence 
*	of events is possible:
*	
*		unreg x at use of delete
*		call delete x
*		first destroy x
*		delete (and thus unreg) an instance variable of x
*		unreg x at definition of delete
*		really delete x
*
*	So I decided just not to inform the user when she's about to delete 
*	an object I didn't know about.
*/
}

extern void _fs_unregister_ATTLC(int atuse, int /*hasbrackets*/, const void *p)
{
	if (regAndUnreg && p)
	{
		regAndUnreg = 0;
		do_unregister(atuse, p);
		regAndUnreg = 1;
	}
}


extern int fs_showall()
{
	int sv = regAndUnreg;
	regAndUnreg = 0;
	int i = 0;
	for (fs_descriptor_ATTLC *dp = first; dp; dp = dp->next, i++)
		dp->print(stderr);
	regAndUnreg = sv;
	return i;
}

struct Mark
{
	int time;
	struct Mark *next, *prev;

	// don't call program's operator new, it will confuse user
	void *operator new(size_t) { return malloc(sizeof(Mark)); }
	void operator delete(void *p) { if (p) free((char*)p); }
};

static Mark *firstMark = 0, *lastMark = 0;

static void pushMark(int t)
{
	int sv = regAndUnreg;
	regAndUnreg = 0;

	if (firstMark == 0)
	{
		firstMark = lastMark = new Mark;
		lastMark->prev = 0;
	}
	else
	{
		lastMark->next = new Mark;
		lastMark->next->prev = lastMark;
		lastMark = lastMark->next;
	}
	lastMark->time = t;
	lastMark->next = 0;

	regAndUnreg = sv;
}
	
static void popMark()
{
	int sv = regAndUnreg;
	regAndUnreg = 0;

	lastMark = lastMark->prev;
	if (lastMark == 0)
	{
		delete firstMark;
		firstMark = 0;
	}
	else
	{
		delete lastMark->next;
		lastMark->next = 0;
	}

	regAndUnreg = sv;
}

extern int fs_mark()
{
	if (lastMark == 0 || (lastMark->time != counter-1))  // don't push multiple marks for the same time
	{
		pushMark(counter-1);
	}
	return counter-1;
}

extern void fs_unmark()
{
	if (lastMark != 0)
		popMark();
}

extern int fs_sincen(int t)
{
	int sv = regAndUnreg;
	regAndUnreg = 0;

	fs_descriptor_ATTLC *dp = 0;

	// First get to the right spot in the container.
	if (last && t < last->onum)
		for (dp = last; dp->prev && t < dp->prev->onum; dp = dp->prev)
			;

	// Now show 'em.
	int i;
	for (i = 0; dp; dp = dp->next, i++)
		dp->print(stderr);

	regAndUnreg = sv;
	return i;
}

extern int fs_since()
{
	if (lastMark == 0)
		return fs_sincen(-1);
	else
		return fs_sincen(lastMark->time);
}

static void showmarks()
{
	int sv = regAndUnreg;
	regAndUnreg = 0;

 	if (firstMark != 0)
	{
		if (firstMark->next != 0)	
			fprintf(stderr, "Marks after: ");
		else	
			fprintf(stderr, "Mark after: ");
		for (Mark *m = firstMark; m != 0; m = m->next)
		{
			fprintf(stderr, "%d", m->time);
			if (m->next)
				fprintf(stderr, ", ");
		}
		fprintf(stderr, "\n");
	}
	regAndUnreg = sv;
}


static int showwatches()
{
	int i = 0;
	for (fs_descriptor_ATTLC *dp = first; dp; dp = dp->next)
	{
		if (dp->watched)
		{
			if (i++ == 0)
				fprintf(stderr, "Delete watches on: ");
			else
				fprintf(stderr, ", ");
			fprintf(stderr, "#%d (%lx)", dp->onum, dp->addr);
		}
	}
	if (i > 0)
		fprintf(stderr, "\n");
	return i;
}

extern void fs_status()
{
	int sv = regAndUnreg;
	regAndUnreg = 0;

	if (!verbose) 
		fprintf(stderr, "Terse.\n");
	if (nwatch) 
		fprintf(stderr, "Watching for news.\n");
	if (dwatch) 
		fprintf(stderr, "Watching for deletes.\n");
	showwatches();
	showmarks();

	regAndUnreg = sv;
}

extern int fs_show(void *p)
{
	int sv = regAndUnreg;
	regAndUnreg = 0;

	fs_descriptor_ATTLC *dp = _fs_get_des_ATTLC(p);
	if (dp != NOT_FOUND)
		dp->print(stderr);
	else
		fprintf(stderr, "No object that I'm aware of at %lx\n", p);

	regAndUnreg = sv;
	return (dp != NOT_FOUND);
}

static int searchFromBeginning(int onum, int w)
{
	for (fs_descriptor_ATTLC *dp = first; dp; dp = dp->next)
	{
		if (dp->onum == onum) 
		{
			dp->watched = w;
			return 1;
		}
		else if (onum < dp->onum)
		{
			fprintf(stderr, "Object #%d has already been deleted.\n", onum);
			return 0;
		}
	}
	return 0;
}

static int searchFromEnd(int onum, int w)
{
	for (fs_descriptor_ATTLC *dp = last; dp; dp = dp->prev)
	{
		if (dp->onum == onum) 
		{
			dp->watched = w;
			return 1;
		}
		else if (onum > dp->onum)
		{
			fprintf(stderr, "Object #%d has already been deleted.\n", onum);
			return 0;
		}
	}
	return 0;
}

static int _fsowatch(int onum, int w)
{
	int sv = regAndUnreg;
	regAndUnreg = 0;

	int ret = 0;
	if (last == 0 || onum > last->onum || onum < first->onum)
	{
		fprintf(stderr, "No object #%d.\n", onum);
	}
	else
	{
		/* find the fs_descriptor_ATTLC for object #onum.  
		* search from closest end of container.
		*/
		if (onum < (last->onum + first->onum)/2)  
			ret = searchFromBeginning(onum, w);
		else
			ret = searchFromEnd(onum, w);
	}

	regAndUnreg = sv;
	return ret;
}

extern void fs_watchall_d()
{
	dwatch = 1;
}
extern void fs_unwatchall_d()
{
	dwatch = 0;
}
extern void fs_watchall_n()
{
	nwatch = 1;
}
extern void fs_unwatchall_n()
{
	nwatch = 0;
}
extern int fs_watch(int onum)
{
	return _fsowatch(onum, 1);
}
extern int fs_unwatch(int onum)
{
	return _fsowatch(onum, 0);
}
extern void fs_help()
{
	fprintf(stderr, "fs_showall() - show information for all objects currently in the freestore\n");
	fprintf(stderr, "fs_show(void *p) - show information for object at memory location p\n");
	fprintf(stderr, "fs_mark() - lay down a mark at the current time\n");
	fprintf(stderr, "fs_unmark() - delete the last mark\n");
	fprintf(stderr, "fs_since() - show information for all objects newed since the last mark\n");
	fprintf(stderr, "fs_sincen(int i) - show information for all objects newed since object number i\n");
	fprintf(stderr, "fs_watch(int i) - set a watch on object number i\n");
	fprintf(stderr, "fs_unwatch(int i) - delete the watch on object number i\n");
	fprintf(stderr, "fs_watchall_d() - watch the freestore for any delete operation\n");
	fprintf(stderr, "fs_unwatchall_d() - stop watching the freestore for delete operations\n");
	fprintf(stderr, "fs_watchall_n() - watch the freestore for any new operation\n");
	fprintf(stderr, "fs_unwatchall_n() - stop watching the freestore for new operations\n");
	fprintf(stderr, "fs_break() - function with empty body, called whenever freestore wants to break\n");
	fprintf(stderr, "fs_status() - show the current settings of marks and watches\n");
	fprintf(stderr, "fs_dbxinit() - print a .dbxinit file which incorporates freestore's functionality\n");
	fprintf(stderr, "              into dbxtool(1)'s button panel\n");
	fprintf(stderr, "fs_help() - this list\n\n");
	fprintf(stderr, "The \"alert!\" modifier on object descriptions means that the object was allocated\n");
	fprintf(stderr, "by a global operator new and is either in the process of being initialized, or\n");
	fprintf(stderr, "is initialized but the line containing the call to new was not compiled with -fs.\n");
	fprintf(stderr, "\n");
}
extern void fs_dbxinit()
{
	fprintf(stderr, "unbutton print\n");
	fprintf(stderr, "unbutton next\n");
	fprintf(stderr, "unbutton step\n");
	fprintf(stderr, "unbutton stop at\n");
	fprintf(stderr, "unbutton stop in\n");
	fprintf(stderr, "unbutton clear\n");
	fprintf(stderr, "unbutton cont\n");
	fprintf(stderr, "unbutton run\n");
	fprintf(stderr, "unbutton where\n");
	fprintf(stderr, "unbutton up\n");
	fprintf(stderr, "unbutton down\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "#button expand print *\n");
	fprintf(stderr, "button ignore next \n");
	fprintf(stderr, "button ignore up\n");
	fprintf(stderr, "button ignore where\n");
	fprintf(stderr, "button lineno stop at\n");
	fprintf(stderr, "button ignore fs\n");
	fprintf(stderr, "button ignore mark\n");
	fprintf(stderr, "button ignore wd\n");
	fprintf(stderr, "button ignore wn\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "button expand print\n");
	fprintf(stderr, "button ignore step\n");
	fprintf(stderr, "button ignore down\n");
	fprintf(stderr, "button ignore dump\n");
	fprintf(stderr, "button lineno clear\n");
	fprintf(stderr, "button ignore since\n");
	fprintf(stderr, "button ignore unmark\n");
	fprintf(stderr, "button ignore unwd\n");
	fprintf(stderr, "button ignore unwn\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "button expand display \n");
	fprintf(stderr, "button ignore cont\n");
	fprintf(stderr, "button ignore \"\"\n");
	fprintf(stderr, "button ignore \"\"\n");
	fprintf(stderr, "button ignore run\n");
	fprintf(stderr, "button ignore \"\"\n");
	fprintf(stderr, "button ignore \"\"\n");
	fprintf(stderr, "button ignore fsstat\n");
	fprintf(stderr, "button ignore setfsbr\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "alias mark \"call fs_mark()\"\n");
	fprintf(stderr, "alias unmark \"call fs_unmark()\"\n");
	fprintf(stderr, "alias fs \"call fs_showall()\"\n");
	fprintf(stderr, "alias since \"call fs_since()\"\n");
	fprintf(stderr, "alias fsstat \"call fs_status()\"\n");
	fprintf(stderr, "alias wd \"call fs_watchall_d()\"\n");
	fprintf(stderr, "alias unwd \"call fs_unwatchall_d()\"\n");
	fprintf(stderr, "alias wn \"call fs_watchall_n()\"\n");
	fprintf(stderr, "alias unwn \"call fs_unwatchall_n()\"\n");
	fprintf(stderr, "alias setfsbr \"stop in fs_break\"");
	fprintf(stderr, "\n");
}

/*
static void showem()
{
	for (fs_descriptor_ATTLC *dp = first; dp; dp = dp->next)
		fprintf(stderr, "%lx\n", dp->addr);
}
*/
« March 2024 »
Su Mo Tu We Th Fr Sa
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: