📄 utility.c
字号:
/*******************************************************/ /* "C" Language Integrated Production System */ /* */ /* CLIPS Version 6.24 06/05/06 */ /* */ /* UTILITY MODULE */ /*******************************************************//*************************************************************//* Purpose: Provides a set of utility functions useful to *//* other modules. Primarily these are the functions for *//* handling periodic garbage collection and appending *//* string data. *//* *//* Principal Programmer(s): *//* Gary D. Riley *//* *//* Contributing Programmer(s): *//* Brian Donnell *//* *//* Revision History: *//* *//* 6.24: Renamed BOOLEAN macro type to intBool. *//* *//*************************************************************/#define _UTILITY_SOURCE_#include "setup.h"#include <ctype.h>#include <stdlib.h>#include <stdio.h>#define _STDIO_INCLUDED_#include <string.h>#include "envrnmnt.h"#include "evaluatn.h"#include "facthsh.h"#include "memalloc.h"#include "multifld.h"#include "prntutil.h"#include "sysdep.h"#include "utility.h"#define MAX_EPHEMERAL_COUNT 1000L#define MAX_EPHEMERAL_SIZE 10240L#define COUNT_INCREMENT 1000L#define SIZE_INCREMENT 10240L/***************************************//* LOCAL INTERNAL FUNCTION DEFINITIONS *//***************************************/ static intBool AddCPFunction(void *,char *,void (*)(void *), int,struct cleanupFunction **,intBool); static intBool RemoveCPFunction(void *,char *,struct cleanupFunction **); static void DeallocateUtilityData(void *);/************************************************//* InitializeUtilityData: Allocates environment *//* data for utility routines. *//************************************************/globle void InitializeUtilityData( void *theEnv) { AllocateEnvironmentData(theEnv,UTILITY_DATA,sizeof(struct utilityData),DeallocateUtilityData); UtilityData(theEnv)->GarbageCollectionLocks = 0; UtilityData(theEnv)->GarbageCollectionHeuristicsEnabled = TRUE; UtilityData(theEnv)->PeriodicFunctionsEnabled = TRUE; UtilityData(theEnv)->YieldFunctionEnabled = TRUE; UtilityData(theEnv)->CurrentEphemeralCountMax = MAX_EPHEMERAL_COUNT; UtilityData(theEnv)->CurrentEphemeralSizeMax = MAX_EPHEMERAL_SIZE; UtilityData(theEnv)->LastEvaluationDepth = -1; } /**************************************************//* DeallocateUtilityData: Deallocates environment *//* data for utility routines. *//**************************************************/static void DeallocateUtilityData( void *theEnv) { struct cleanupFunction *tmpPtr, *nextPtr; struct trackedMemory *tmpTM, *nextTM; tmpTM = UtilityData(theEnv)->trackList; while (tmpTM != NULL) { nextTM = tmpTM->next; genfree(theEnv,tmpTM->theMemory,tmpTM->memSize); rtn_struct(theEnv,trackedMemory,tmpTM); tmpTM = nextTM; } tmpPtr = UtilityData(theEnv)->ListOfPeriodicFunctions; while (tmpPtr != NULL) { nextPtr = tmpPtr->next; rtn_struct(theEnv,cleanupFunction,tmpPtr); tmpPtr = nextPtr; } tmpPtr = UtilityData(theEnv)->ListOfCleanupFunctions; while (tmpPtr != NULL) { nextPtr = tmpPtr->next; rtn_struct(theEnv,cleanupFunction,tmpPtr); tmpPtr = nextPtr; } }/*************************************************************//* PeriodicCleanup: Returns garbage created during execution *//* that has not been returned to the memory pool yet. The *//* cleanup is normally deferred so that an executing rule *//* can still access these data structures. Always calls a *//* series of functions that should be called periodically. *//* Usually used by interfaces to update displays. *//*************************************************************/globle void PeriodicCleanup( void *theEnv, intBool cleanupAllDepths, intBool useHeuristics) { int oldDepth = -1; struct cleanupFunction *cleanupPtr,*periodPtr; /*===================================*/ /* Don't use heuristics if disabled. */ /*===================================*/ if (! UtilityData(theEnv)->GarbageCollectionHeuristicsEnabled) { useHeuristics = FALSE; } /*=============================================*/ /* Call functions for handling periodic tasks. */ /*=============================================*/ if (UtilityData(theEnv)->PeriodicFunctionsEnabled) { for (periodPtr = UtilityData(theEnv)->ListOfPeriodicFunctions; periodPtr != NULL; periodPtr = periodPtr->next) { if (periodPtr->environmentAware) { (*periodPtr->ip)(theEnv); } else { (* (void (*)(void)) periodPtr->ip)(); } } } /*===================================================*/ /* If the last level we performed cleanup was deeper */ /* than the current level, reset the values used by */ /* the heuristics to determine if garbage collection */ /* should be performed. If the heuristic values had */ /* to be incremented because there was no garbage */ /* that could be cleaned up, we don't want to keep */ /* those same high values permanently so we reset */ /* them when we go back to a lower evaluation depth. */ /*===================================================*/ if (UtilityData(theEnv)->LastEvaluationDepth > EvaluationData(theEnv)->CurrentEvaluationDepth) { UtilityData(theEnv)->LastEvaluationDepth = EvaluationData(theEnv)->CurrentEvaluationDepth; UtilityData(theEnv)->CurrentEphemeralCountMax = MAX_EPHEMERAL_COUNT; UtilityData(theEnv)->CurrentEphemeralSizeMax = MAX_EPHEMERAL_SIZE; } /*======================================================*/ /* If we're using heuristics to determine if garbage */ /* collection to occur, then check to see if enough */ /* garbage has been created to make cleanup worthwhile. */ /*======================================================*/ if (UtilityData(theEnv)->GarbageCollectionLocks > 0) return; if (useHeuristics && (UtilityData(theEnv)->EphemeralItemCount < UtilityData(theEnv)->CurrentEphemeralCountMax) && (UtilityData(theEnv)->EphemeralItemSize < UtilityData(theEnv)->CurrentEphemeralSizeMax)) { return; } /*==========================================================*/ /* If cleanup is being performed at all depths, rather than */ /* just the current evaluation depth, then temporarily set */ /* the evaluation depth to a level that will force cleanup */ /* at all depths. */ /*==========================================================*/ if (cleanupAllDepths) { oldDepth = EvaluationData(theEnv)->CurrentEvaluationDepth; EvaluationData(theEnv)->CurrentEvaluationDepth = -1; } /*=============================================*/ /* Free up multifield values no longer in use. */ /*=============================================*/ FlushMultifields(theEnv); /*=====================================*/ /* Call the list of cleanup functions. */ /*=====================================*/ for (cleanupPtr = UtilityData(theEnv)->ListOfCleanupFunctions; cleanupPtr != NULL; cleanupPtr = cleanupPtr->next) { if (cleanupPtr->environmentAware) { (*cleanupPtr->ip)(theEnv); } else { (* (void (*)(void)) cleanupPtr->ip)(); } } /*================================================*/ /* Free up atomic values that are no longer used. */ /*================================================*/ RemoveEphemeralAtoms(theEnv); /*=========================================*/ /* Restore the evaluation depth if cleanup */ /* was performed on all depths. */ /*=========================================*/ if (cleanupAllDepths) EvaluationData(theEnv)->CurrentEvaluationDepth = oldDepth; /*============================================================*/ /* If very little memory was freed up, then increment the */ /* values used by the heuristics so that we don't continually */ /* try to free up memory that isn't being released. */ /*============================================================*/ if ((UtilityData(theEnv)->EphemeralItemCount + COUNT_INCREMENT) > UtilityData(theEnv)->CurrentEphemeralCountMax) { UtilityData(theEnv)->CurrentEphemeralCountMax = UtilityData(theEnv)->EphemeralItemCount + COUNT_INCREMENT; } if ((UtilityData(theEnv)->EphemeralItemSize + SIZE_INCREMENT) > UtilityData(theEnv)->CurrentEphemeralSizeMax) { UtilityData(theEnv)->CurrentEphemeralSizeMax = UtilityData(theEnv)->EphemeralItemSize + SIZE_INCREMENT; } /*===============================================================*/ /* Remember the evaluation depth at which garbage collection was */ /* last performed. This information is used for resetting the */ /* ephemeral count and size numbers used by the heuristics. */ /*===============================================================*/ UtilityData(theEnv)->LastEvaluationDepth = EvaluationData(theEnv)->CurrentEvaluationDepth; }/***************************************************//* AddCleanupFunction: Adds a function to the list *//* of functions called to perform cleanup such *//* as returning free memory to the memory pool. *//***************************************************/globle intBool AddCleanupFunction( void *theEnv, char *name, void (*theFunction)(void *), int priority) { return(AddCPFunction(theEnv,name,theFunction,priority,&UtilityData(theEnv)->ListOfCleanupFunctions,TRUE)); }#if (! ENVIRONMENT_API_ONLY) && ALLOW_ENVIRONMENT_GLOBALS/****************************************************//* AddPeriodicFunction: Adds a function to the list *//* of functions called to handle periodic tasks. *//****************************************************/globle intBool AddPeriodicFunction( char *name, void (*theFunction)(void), int priority) { void *theEnv; theEnv = GetCurrentEnvironment(); return(AddCPFunction(theEnv,name,(void (*)(void *)) theFunction,priority, &UtilityData(theEnv)->ListOfPeriodicFunctions,FALSE)); }#endif/*******************************************************//* EnvAddPeriodicFunction: Adds a function to the list *//* of functions called to handle periodic tasks. *//*******************************************************/globle intBool EnvAddPeriodicFunction( void *theEnv, char *name, void (*theFunction)(void *), int priority) { return(AddCPFunction(theEnv,name,theFunction,priority,&UtilityData(theEnv)->ListOfPeriodicFunctions,TRUE)); }/**********************************//* AddCPFunction: Adds a function *//* to a list of functions. *//**********************************/static intBool AddCPFunction( void *theEnv, char *name, void (*theFunction)(void *), int priority, struct cleanupFunction **head, intBool environmentAware) { struct cleanupFunction *newPtr, *currentPtr, *lastPtr = NULL; newPtr = get_struct(theEnv,cleanupFunction); newPtr->name = name; newPtr->ip = theFunction; newPtr->priority = priority; newPtr->environmentAware = (short) environmentAware; if (*head == NULL) { newPtr->next = NULL; *head = newPtr; return(1); } currentPtr = *head; while ((currentPtr != NULL) ? (priority < currentPtr->priority) : FALSE) { lastPtr = currentPtr; currentPtr = currentPtr->next; } if (lastPtr == NULL) { newPtr->next = *head; *head = newPtr; } else { newPtr->next = currentPtr; lastPtr->next = newPtr; } return(1); }/*******************************************************//* RemoveCleanupFunction: Removes a function from the *//* list of functions called to perform cleanup such *//* as returning free memory to the memory pool. *//*******************************************************/globle intBool RemoveCleanupFunction( void *theEnv, char *name) { return(RemoveCPFunction(theEnv,name,&UtilityData(theEnv)->ListOfCleanupFunctions)); }/**********************************************************//* EnvRemovePeriodicFunction: Removes a function from the *//* list of functions called to handle periodic tasks. *//**********************************************************/globle intBool EnvRemovePeriodicFunction( void *theEnv, char *name) { return(RemoveCPFunction(theEnv,name,&UtilityData(theEnv)->ListOfPeriodicFunctions)); }/****************************************//* RemoveCPFunction: Removes a function *//* from a list of functions. *//****************************************/static intBool RemoveCPFunction( void *theEnv, char *name, struct cleanupFunction **head) { struct cleanupFunction *currentPtr, *lastPtr; lastPtr = NULL; currentPtr = *head; while (currentPtr != NULL) { if (strcmp(name,currentPtr->name) == 0) { if (lastPtr == NULL) { *head = currentPtr->next; } else { lastPtr->next = currentPtr->next; } rtn_struct(theEnv,cleanupFunction,currentPtr); return(TRUE); } lastPtr = currentPtr; currentPtr = currentPtr->next; } return(FALSE); }/*****************************************************//* StringPrintForm: Generates printed representation *//* of a string. Replaces / with // and " with /". *//*****************************************************/globle char *StringPrintForm( void *theEnv, char *str) { int i = 0; size_t pos = 0; size_t max = 0; char *theString = NULL; void *thePtr; theString = ExpandStringWithChar(theEnv,'"',theString,&pos,&max,max+80); while (str[i] != EOS) { if ((str[i] == '"') || (str[i] == '\\')) { theString = ExpandStringWithChar(theEnv,'\\',theString,&pos,&max,max+80); theString = ExpandStringWithChar(theEnv,str[i],theString,&pos,&max,max+80); } else { theString = ExpandStringWithChar(theEnv,str[i],theString,&pos,&max,max+80); } i++; } theString = ExpandStringWithChar(theEnv,'"',theString,&pos,&max,max+80); thePtr = EnvAddSymbol(theEnv,theString); rm(theEnv,theString,max); return(ValueToString(thePtr)); }/***********************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -