/* * Copyright (c) 2001-2023 Julien Nadeau Carriere * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Agar-Core initialization routines. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef AG_THREADS # include # include # include #endif #include #include #include #include #include #ifndef _WIN32 # include #endif #if defined(__FreeBSD__) && defined(HAVE_CLOCK_GETTIME) # include #elif defined(HAVE_GETTIMEOFDAY) # include #endif /* Print the object validity signature on initialization. */ /* #define DEBUG_SIGNATURE */ #ifdef AG_THREADS pthread_mutexattr_t agRecursiveMutexAttr; /* Recursive mutex attributes */ AG_Thread agEventThread; /* Event-processing thread */ #endif #ifdef AG_SERIALIZATION AG_Config *agConfig = NULL; /* Global Agar config data */ #endif void (*agAtexitFunc)(void) = NULL; /* User exit function */ void (*agAtexitFuncEv)(AG_Event *) = NULL; /* User exit handler */ char *agProgName = NULL; /* Optional application name */ #ifdef AG_VERBOSITY int agVerbose = 0; /* Verbose console output */ #endif #ifdef AG_TIMERS int agSoftTimers = 0; /* Disable hardware timers */ #endif const char *agMemoryModelNames[] = { N_("Small"), /* AG_SMALL */ N_("Medium"), /* AG_MEDIUM */ N_("Large") /* AG_LARGE */ }; /* Initialize the Agar-Core library */ int AG_InitCore(const char *progname, Uint flags) { #ifdef AG_SERIALIZATION if (agConfig != NULL) /* AG_InitCore() was already called */ return (0); #endif /* Process option flags. */ #ifdef AG_VERBOSITY if (flags & AG_VERBOSE) agVerbose = 1; #endif #ifdef AG_TIMERS if (flags & AG_SOFT_TIMERS) agSoftTimers = 1; #endif /* Set the program name (if not NULL). */ if (progname != NULL) { if ((agProgName = TryStrdup(progname)) == NULL) return (-1); } else { agProgName = NULL; } /* Set up the language translation. */ #ifdef ENABLE_NLS bindtextdomain("agar", LOCALEDIR); bind_textdomain_codeset("agar", "UTF-8"); textdomain("agar"); #endif /* Initialize the AG_Error(3) and AG_String(3) interfaces. */ if (AG_InitErrorSubsystem() == -1 || AG_InitStringSubsystem() == -1) return (-1); /* Initialize the AG_Event(3) subsystem. */ #ifdef AG_EVENT_LOOP if (AG_InitEventSubsystem(flags) == -1) return (-1); #endif /* Fetch CPU information. */ AG_GetCPUInfo(&agCPU); /* Initialize POSIX threads. */ #ifdef AG_THREADS agEventThread = AG_ThreadSelf(); /* Main thread */ # ifdef _XBOX ptw32_processInitialize(); # endif pthread_mutexattr_init(&agRecursiveMutexAttr); # ifdef HAVE_PTHREAD_MUTEX_RECURSIVE_NP pthread_mutexattr_settype(&agRecursiveMutexAttr, PTHREAD_MUTEX_RECURSIVE_NP); # else pthread_mutexattr_settype(&agRecursiveMutexAttr, PTHREAD_MUTEX_RECURSIVE); # endif # ifdef AG_ENABLE_DSO AG_MutexInitRecursive(&agDSOLock); # endif #endif /* AG_THREADS */ /* Initialize core Agar object classes. */ AG_InitClassTbl(); #ifdef AG_SERIALIZATION AG_RegisterClass(&agConfigClass); AG_RegisterClass(&agDbClass); # if defined(HAVE_DB4) AG_RegisterClass(&agDbHashClass); AG_RegisterClass(&agDbBtreeClass); # endif #endif /* AG_SERIALIZATION */ /* Select the default AG_Time(3) backend. */ #if defined(_WIN32) AG_SetTimeOps(&agTimeOps_win32); #elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_NANOSLEEP) AG_SetTimeOps(&agTimeOps_posix); #elif defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SELECT) AG_SetTimeOps(&agTimeOps_gettimeofday); #else AG_SetTimeOps(&agTimeOps_dummy); #endif #if defined(__FreeBSD__) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_SECOND) { struct timespec t; clock_gettime(CLOCK_SECOND, &t); # if AG_BYTEORDER == AG_BIG_ENDIAN agObjectSignature = (t.tv_sec << 1) * (t.tv_sec & 0xff000000); agNonObjectSignature = (t.tv_sec << 1) * (t.tv_sec & 0xf0000000); # else agObjectSignature = (t.tv_sec << 1) * (t.tv_sec & 0x000000ff); agNonObjectSignature = (t.tv_sec << 1) * (t.tv_sec & 0x0000000f); # endif } #elif defined(HAVE_GETTIMEOFDAY) { struct timeval t; gettimeofday(&t, NULL); # if AG_BYTEORDER == AG_BIG_ENDIAN agObjectSignature = (t.tv_sec << 1) * (t.tv_sec & 0xff000000); agNonObjectSignature = (t.tv_sec << 1) * (t.tv_sec & 0xf0000000); # else agObjectSignature = (t.tv_sec << 1) * (t.tv_sec & 0x000000ff); agNonObjectSignature = (t.tv_sec << 1) * (t.tv_sec & 0x0000000f); # endif } #else /* TODO */ agObjectSignature = 0x2A538247; agNonObjectSignature = 0x5B317CF4; #endif #ifdef DEBUG_SIGNATURE Debug(NULL, "Signature (object) = 0x%08x\n", agObjectSignature); Debug(NULL, "Signature (nonobject) = 0x%08x\n", agNonObjectSignature); #endif /* * Set the user info access method. Select the fastest method that can * provide us with a path to some writeable home directory (for example, * on Unix we prefer getenv(3) to getpwent(3) for best efficiency). */ #ifdef AG_USER # if defined(_XBOX) AG_SetUserOps(&agUserOps_xbox); # elif defined(_WIN32) && defined(HAVE_CSIDL) AG_SetUserOps(&agUserOps_win32); # elif defined(HAVE_GETENV) || (defined(HAVE_GETPWUID) && defined(HAVE_GETUID)) if (flags & AG_POSIX_USERS) { /* Prefer posix */ # if defined(HAVE_GETPWUID) && defined(HAVE_GETUID) AG_SetUserOps(&agUserOps_posix); # else AG_SetUserOps(&agUserOps_getenv); # endif } else { /* Prefer getenv */ # if defined(HAVE_GETENV) AG_SetUserOps(&agUserOps_getenv); # else AG_SetUserOps(&agUserOps_posix); # endif } # else /* !AG_USER */ AG_SetUserOps(&agUserOps_dummy); # endif #endif /* AG_USER */ /* Initialize the AG_Timer(3) subsystem. */ #ifdef AG_TIMERS AG_InitTimers(); #endif #ifdef AG_SERIALIZATION /* Initialize the AG_DataSource(3) interface. */ AG_DataSourceInitSubsystem(); /* Initialize the global AG_Config(3) object. */ if ((agConfig = TryMalloc(sizeof(AG_Config))) == NULL || AG_ConfigInit(agConfig, flags) == -1) return (-1); #endif return (0); } /* Register a function to invoke in AG_Quit(). */ void AG_AtExitFunc(void (*func)(void)) { agAtexitFunc = func; } void AG_AtExitFuncEv(void (*func)(AG_Event *)) { agAtexitFuncEv = func; } /* Immediately terminate the application. */ void AG_Quit(void) { AG_Destroy(); exit(0); } /* Clean up the resources allocated by Agar-Core. */ void AG_Destroy(void) { #ifdef AG_SERIALIZATION if (agConfig == NULL) return; #endif if (agAtexitFunc != NULL) { agAtexitFunc(); } if (agAtexitFuncEv != NULL) { agAtexitFuncEv(NULL); } #ifdef AG_USER if (agUserOps != NULL && agUserOps->destroy != NULL) { agUserOps->destroy(); agUserOps = NULL; } #endif #ifdef AG_SERIALIZATION AG_ObjectDestroy(agConfig); agConfig = NULL; AG_DataSourceDestroySubsystem(); #endif #ifdef AG_TIMERS AG_DestroyTimers(); #endif AG_DestroyClassTbl(); #ifdef AG_THREADS pthread_mutexattr_destroy(&agRecursiveMutexAttr); # ifdef AG_ENABLE_DSO AG_MutexDestroy(&agDSOLock); # endif #endif #ifdef AG_EVENT_LOOP AG_DestroyEventSubsystem(); #endif AG_DestroyStringSubsystem(); AG_DestroyErrorSubsystem(); Free(agProgName); agProgName = NULL; } void AG_GetVersion(AG_AgarVersion *ver) { ver->major = AGAR_MAJOR_VERSION; ver->minor = AGAR_MINOR_VERSION; ver->patch = AGAR_PATCHLEVEL; ver->rev = 0; ver->release = RELEASE; }