00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "../game/q_shared.h"
00025 #include "qcommon.h"
00026 #include <setjmp.h>
00027 #ifdef __linux__
00028 #include <netinet/in.h>
00029 #else
00030 #if defined(MACOS_X)
00031 #include <netinet/in.h>
00032 #else
00033 #include <winsock.h>
00034 #endif
00035 #endif
00036
00037 int demo_protocols[] =
00038 { 66, 67, 68, 0 };
00039
00040 #define MAX_NUM_ARGVS 50
00041
00042 #define MIN_DEDICATED_COMHUNKMEGS 1
00043 #define MIN_COMHUNKMEGS 56
00044 #ifdef MACOS_X
00045 #define DEF_COMHUNKMEGS "64"
00046 #define DEF_COMZONEMEGS "24"
00047 #else
00048 #define DEF_COMHUNKMEGS "56"
00049 #define DEF_COMZONEMEGS "16"
00050 #endif
00051
00052 int com_argc;
00053 char *com_argv[MAX_NUM_ARGVS+1];
00054
00055 jmp_buf abortframe;
00056
00057
00058 FILE *debuglogfile;
00059 static fileHandle_t logfile;
00060 fileHandle_t com_journalFile;
00061 fileHandle_t com_journalDataFile;
00062
00063 cvar_t *com_viewlog;
00064 cvar_t *com_speeds;
00065 cvar_t *com_developer;
00066 cvar_t *com_dedicated;
00067 cvar_t *com_timescale;
00068 cvar_t *com_fixedtime;
00069 cvar_t *com_dropsim;
00070 cvar_t *com_journal;
00071 cvar_t *com_maxfps;
00072 cvar_t *com_timedemo;
00073 cvar_t *com_sv_running;
00074 cvar_t *com_cl_running;
00075 cvar_t *com_logfile;
00076 cvar_t *com_showtrace;
00077 cvar_t *com_version;
00078 cvar_t *com_blood;
00079 cvar_t *com_buildScript;
00080 cvar_t *com_introPlayed;
00081 cvar_t *cl_paused;
00082 cvar_t *sv_paused;
00083 cvar_t *com_cameraMode;
00084 #if defined(_WIN32) && defined(_DEBUG)
00085 cvar_t *com_noErrorInterrupt;
00086 #endif
00087
00088
00089 int time_game;
00090 int time_frontend;
00091 int time_backend;
00092
00093 int com_frameTime;
00094 int com_frameMsec;
00095 int com_frameNumber;
00096
00097 qboolean com_errorEntered;
00098 qboolean com_fullyInitialized;
00099
00100 char com_errorMessage[MAXPRINTMSG];
00101
00102 void Com_WriteConfig_f( void );
00103 void CIN_CloseAllVideos();
00104
00105
00106
00107 static char *rd_buffer;
00108 static int rd_buffersize;
00109 static void (*rd_flush)( char *buffer );
00110
00111 void Com_BeginRedirect (char *buffer, int buffersize, void (*flush)( char *) )
00112 {
00113 if (!buffer || !buffersize || !flush)
00114 return;
00115 rd_buffer = buffer;
00116 rd_buffersize = buffersize;
00117 rd_flush = flush;
00118
00119 *rd_buffer = 0;
00120 }
00121
00122 void Com_EndRedirect (void)
00123 {
00124 if ( rd_flush ) {
00125 rd_flush(rd_buffer);
00126 }
00127
00128 rd_buffer = NULL;
00129 rd_buffersize = 0;
00130 rd_flush = NULL;
00131 }
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 void QDECL Com_Printf( const char *fmt, ... ) {
00144 va_list argptr;
00145 char msg[MAXPRINTMSG];
00146 static qboolean opening_qconsole = qfalse;
00147
00148 va_start (argptr,fmt);
00149 Q_vsnprintf (msg, sizeof(msg), fmt, argptr);
00150 va_end (argptr);
00151
00152 if ( rd_buffer ) {
00153 if ((strlen (msg) + strlen(rd_buffer)) > (rd_buffersize - 1)) {
00154 rd_flush(rd_buffer);
00155 *rd_buffer = 0;
00156 }
00157 Q_strcat(rd_buffer, rd_buffersize, msg);
00158
00159
00160
00161 return;
00162 }
00163
00164
00165 if ( com_dedicated && !com_dedicated->integer ) {
00166 CL_ConsolePrint( msg );
00167 }
00168
00169
00170 Sys_Print( msg );
00171
00172
00173 if ( com_logfile && com_logfile->integer ) {
00174
00175
00176 if ( !logfile && FS_Initialized() && !opening_qconsole) {
00177 struct tm *newtime;
00178 time_t aclock;
00179
00180 opening_qconsole = qtrue;
00181
00182 time( &aclock );
00183 newtime = localtime( &aclock );
00184
00185 logfile = FS_FOpenFileWrite( "qconsole.log" );
00186 Com_Printf( "logfile opened on %s\n", asctime( newtime ) );
00187 if ( com_logfile->integer > 1 ) {
00188
00189
00190 FS_ForceFlush(logfile);
00191 }
00192
00193 opening_qconsole = qfalse;
00194 }
00195 if ( logfile && FS_Initialized()) {
00196 FS_Write(msg, strlen(msg), logfile);
00197 }
00198 }
00199 }
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209 void QDECL Com_DPrintf( const char *fmt, ...) {
00210 va_list argptr;
00211 char msg[MAXPRINTMSG];
00212
00213 if ( !com_developer || !com_developer->integer ) {
00214 return;
00215 }
00216
00217 va_start (argptr,fmt);
00218 Q_vsnprintf (msg, sizeof(msg), fmt, argptr);
00219 va_end (argptr);
00220
00221 Com_Printf ("%s", msg);
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 void QDECL Com_Error( int code, const char *fmt, ... ) {
00233 va_list argptr;
00234 static int lastErrorTime;
00235 static int errorCount;
00236 int currentTime;
00237
00238 #if defined(_WIN32) && defined(_DEBUG)
00239 if ( code != ERR_DISCONNECT && code != ERR_NEED_CD ) {
00240 if (!com_noErrorInterrupt->integer) {
00241 __asm {
00242 int 0x03
00243 }
00244 }
00245 }
00246 #endif
00247
00248
00249
00250 if ( com_buildScript && com_buildScript->integer ) {
00251 code = ERR_FATAL;
00252 }
00253
00254
00255 FS_PureServerSetLoadedPaks( "", "" );
00256
00257
00258 currentTime = Sys_Milliseconds();
00259 if ( currentTime - lastErrorTime < 100 ) {
00260 if ( ++errorCount > 3 ) {
00261 code = ERR_FATAL;
00262 }
00263 } else {
00264 errorCount = 0;
00265 }
00266 lastErrorTime = currentTime;
00267
00268 if ( com_errorEntered ) {
00269 Sys_Error( "recursive error after: %s", com_errorMessage );
00270 }
00271 com_errorEntered = qtrue;
00272
00273 va_start (argptr,fmt);
00274 vsprintf (com_errorMessage,fmt,argptr);
00275 va_end (argptr);
00276
00277 if ( code != ERR_DISCONNECT && code != ERR_NEED_CD ) {
00278 Cvar_Set("com_errorMessage", com_errorMessage);
00279 }
00280
00281 if ( code == ERR_SERVERDISCONNECT ) {
00282 CL_Disconnect( qtrue );
00283 CL_FlushMemory( );
00284 com_errorEntered = qfalse;
00285 longjmp (abortframe, -1);
00286 } else if ( code == ERR_DROP || code == ERR_DISCONNECT ) {
00287 Com_Printf ("********************\nERROR: %s\n********************\n", com_errorMessage);
00288 SV_Shutdown (va("Server crashed: %s\n", com_errorMessage));
00289 CL_Disconnect( qtrue );
00290 CL_FlushMemory( );
00291 com_errorEntered = qfalse;
00292 longjmp (abortframe, -1);
00293 } else if ( code == ERR_NEED_CD ) {
00294 SV_Shutdown( "Server didn't have CD\n" );
00295 if ( com_cl_running && com_cl_running->integer ) {
00296 CL_Disconnect( qtrue );
00297 CL_FlushMemory( );
00298 com_errorEntered = qfalse;
00299 CL_CDDialog();
00300 } else {
00301 Com_Printf("Server didn't have CD\n" );
00302 }
00303 longjmp (abortframe, -1);
00304 } else {
00305 CL_Shutdown ();
00306 SV_Shutdown (va("Server fatal crashed: %s\n", com_errorMessage));
00307 }
00308
00309 Com_Shutdown ();
00310
00311 Sys_Error ("%s", com_errorMessage);
00312 }
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 void Com_Quit_f( void ) {
00324
00325 if ( !com_errorEntered ) {
00326 SV_Shutdown ("Server quit\n");
00327 CL_Shutdown ();
00328 Com_Shutdown ();
00329 FS_Shutdown(qtrue);
00330 }
00331 Sys_Quit ();
00332 }
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353 #define MAX_CONSOLE_LINES 32
00354 int com_numConsoleLines;
00355 char *com_consoleLines[MAX_CONSOLE_LINES];
00356
00357
00358
00359
00360
00361
00362
00363
00364 void Com_ParseCommandLine( char *commandLine ) {
00365 int inq = 0;
00366 com_consoleLines[0] = commandLine;
00367 com_numConsoleLines = 1;
00368
00369 while ( *commandLine ) {
00370 if (*commandLine == '"') {
00371 inq = !inq;
00372 }
00373
00374
00375 if ( (*commandLine == '+' && !inq) || *commandLine == '\n' || *commandLine == '\r' ) {
00376 if ( com_numConsoleLines == MAX_CONSOLE_LINES ) {
00377 return;
00378 }
00379 com_consoleLines[com_numConsoleLines] = commandLine + 1;
00380 com_numConsoleLines++;
00381 *commandLine = 0;
00382 }
00383 commandLine++;
00384 }
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 qboolean Com_SafeMode( void ) {
00397 int i;
00398
00399 for ( i = 0 ; i < com_numConsoleLines ; i++ ) {
00400 Cmd_TokenizeString( com_consoleLines[i] );
00401 if ( !Q_stricmp( Cmd_Argv(0), "safe" )
00402 || !Q_stricmp( Cmd_Argv(0), "cvar_restart" ) ) {
00403 com_consoleLines[i][0] = 0;
00404 return qtrue;
00405 }
00406 }
00407 return qfalse;
00408 }
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422 void Com_StartupVariable( const char *match ) {
00423 int i;
00424 char *s;
00425 cvar_t *cv;
00426
00427 for (i=0 ; i < com_numConsoleLines ; i++) {
00428 Cmd_TokenizeString( com_consoleLines[i] );
00429 if ( strcmp( Cmd_Argv(0), "set" ) ) {
00430 continue;
00431 }
00432
00433 s = Cmd_Argv(1);
00434 if ( !match || !strcmp( s, match ) ) {
00435 Cvar_Set( s, Cmd_Argv(2) );
00436 cv = Cvar_Get( s, "", 0 );
00437 cv->flags |= CVAR_USER_CREATED;
00438
00439 }
00440 }
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455 qboolean Com_AddStartupCommands( void ) {
00456 int i;
00457 qboolean added;
00458
00459 added = qfalse;
00460
00461 for (i=0 ; i < com_numConsoleLines ; i++) {
00462 if ( !com_consoleLines[i] || !com_consoleLines[i][0] ) {
00463 continue;
00464 }
00465
00466
00467 if ( Q_stricmpn( com_consoleLines[i], "set", 3 ) ) {
00468 added = qtrue;
00469 }
00470 Cbuf_AddText( com_consoleLines[i] );
00471 Cbuf_AddText( "\n" );
00472 }
00473
00474 return added;
00475 }
00476
00477
00478
00479
00480 void Info_Print( const char *s ) {
00481 char key[512];
00482 char value[512];
00483 char *o;
00484 int l;
00485
00486 if (*s == '\\')
00487 s++;
00488 while (*s)
00489 {
00490 o = key;
00491 while (*s && *s != '\\')
00492 *o++ = *s++;
00493
00494 l = o - key;
00495 if (l < 20)
00496 {
00497 Com_Memset (o, ' ', 20-l);
00498 key[20] = 0;
00499 }
00500 else
00501 *o = 0;
00502 Com_Printf ("%s", key);
00503
00504 if (!*s)
00505 {
00506 Com_Printf ("MISSING VALUE\n");
00507 return;
00508 }
00509
00510 o = value;
00511 s++;
00512 while (*s && *s != '\\')
00513 *o++ = *s++;
00514 *o = 0;
00515
00516 if (*s)
00517 s++;
00518 Com_Printf ("%s\n", value);
00519 }
00520 }
00521
00522
00523
00524
00525
00526
00527 char *Com_StringContains(char *str1, char *str2, int casesensitive) {
00528 int len, i, j;
00529
00530 len = strlen(str1) - strlen(str2);
00531 for (i = 0; i <= len; i++, str1++) {
00532 for (j = 0; str2[j]; j++) {
00533 if (casesensitive) {
00534 if (str1[j] != str2[j]) {
00535 break;
00536 }
00537 }
00538 else {
00539 if (toupper(str1[j]) != toupper(str2[j])) {
00540 break;
00541 }
00542 }
00543 }
00544 if (!str2[j]) {
00545 return str1;
00546 }
00547 }
00548 return NULL;
00549 }
00550
00551
00552
00553
00554
00555
00556 int Com_Filter(char *filter, char *name, int casesensitive)
00557 {
00558 char buf[MAX_TOKEN_CHARS];
00559 char *ptr;
00560 int i, found;
00561
00562 while(*filter) {
00563 if (*filter == '*') {
00564 filter++;
00565 for (i = 0; *filter; i++) {
00566 if (*filter == '*' || *filter == '?') break;
00567 buf[i] = *filter;
00568 filter++;
00569 }
00570 buf[i] = '\0';
00571 if (strlen(buf)) {
00572 ptr = Com_StringContains(name, buf, casesensitive);
00573 if (!ptr) return qfalse;
00574 name = ptr + strlen(buf);
00575 }
00576 }
00577 else if (*filter == '?') {
00578 filter++;
00579 name++;
00580 }
00581 else if (*filter == '[' && *(filter+1) == '[') {
00582 filter++;
00583 }
00584 else if (*filter == '[') {
00585 filter++;
00586 found = qfalse;
00587 while(*filter && !found) {
00588 if (*filter == ']' && *(filter+1) != ']') break;
00589 if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) {
00590 if (casesensitive) {
00591 if (*name >= *filter && *name <= *(filter+2)) found = qtrue;
00592 }
00593 else {
00594 if (toupper(*name) >= toupper(*filter) &&
00595 toupper(*name) <= toupper(*(filter+2))) found = qtrue;
00596 }
00597 filter += 3;
00598 }
00599 else {
00600 if (casesensitive) {
00601 if (*filter == *name) found = qtrue;
00602 }
00603 else {
00604 if (toupper(*filter) == toupper(*name)) found = qtrue;
00605 }
00606 filter++;
00607 }
00608 }
00609 if (!found) return qfalse;
00610 while(*filter) {
00611 if (*filter == ']' && *(filter+1) != ']') break;
00612 filter++;
00613 }
00614 filter++;
00615 name++;
00616 }
00617 else {
00618 if (casesensitive) {
00619 if (*filter != *name) return qfalse;
00620 }
00621 else {
00622 if (toupper(*filter) != toupper(*name)) return qfalse;
00623 }
00624 filter++;
00625 name++;
00626 }
00627 }
00628 return qtrue;
00629 }
00630
00631
00632
00633
00634
00635
00636 int Com_FilterPath(char *filter, char *name, int casesensitive)
00637 {
00638 int i;
00639 char new_filter[MAX_QPATH];
00640 char new_name[MAX_QPATH];
00641
00642 for (i = 0; i < MAX_QPATH-1 && filter[i]; i++) {
00643 if ( filter[i] == '\\' || filter[i] == ':' ) {
00644 new_filter[i] = '/';
00645 }
00646 else {
00647 new_filter[i] = filter[i];
00648 }
00649 }
00650 new_filter[i] = '\0';
00651 for (i = 0; i < MAX_QPATH-1 && name[i]; i++) {
00652 if ( name[i] == '\\' || name[i] == ':' ) {
00653 new_name[i] = '/';
00654 }
00655 else {
00656 new_name[i] = name[i];
00657 }
00658 }
00659 new_name[i] = '\0';
00660 return Com_Filter(new_filter, new_name, casesensitive);
00661 }
00662
00663
00664
00665
00666
00667
00668 int Com_HashKey(char *string, int maxlen) {
00669 int register hash, i;
00670
00671 hash = 0;
00672 for (i = 0; i < maxlen && string[i] != '\0'; i++) {
00673 hash += string[i] * (119 + i);
00674 }
00675 hash = (hash ^ (hash >> 10) ^ (hash >> 20));
00676 return hash;
00677 }
00678
00679
00680
00681
00682
00683
00684 int Com_RealTime(qtime_t *qtime) {
00685 time_t t;
00686 struct tm *tms;
00687
00688 t = time(NULL);
00689 if (!qtime)
00690 return t;
00691 tms = localtime(&t);
00692 if (tms) {
00693 qtime->tm_sec = tms->tm_sec;
00694 qtime->tm_min = tms->tm_min;
00695 qtime->tm_hour = tms->tm_hour;
00696 qtime->tm_mday = tms->tm_mday;
00697 qtime->tm_mon = tms->tm_mon;
00698 qtime->tm_year = tms->tm_year;
00699 qtime->tm_wday = tms->tm_wday;
00700 qtime->tm_yday = tms->tm_yday;
00701 qtime->tm_isdst = tms->tm_isdst;
00702 }
00703 return t;
00704 }
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722 #define ZONEID 0x1d4a11
00723 #define MINFRAGMENT 64
00724
00725 typedef struct zonedebug_s {
00726 char *label;
00727 char *file;
00728 int line;
00729 int allocSize;
00730 } zonedebug_t;
00731
00732 typedef struct memblock_s {
00733 int size;
00734 int tag;
00735 struct memblock_s *next, *prev;
00736 int id;
00737 #ifdef ZONE_DEBUG
00738 zonedebug_t d;
00739 #endif
00740 } memblock_t;
00741
00742 typedef struct {
00743 int size;
00744 int used;
00745 memblock_t blocklist;
00746 memblock_t *rover;
00747 } memzone_t;
00748
00749
00750 memzone_t *mainzone;
00751
00752
00753 memzone_t *smallzone;
00754
00755 void Z_CheckHeap( void );
00756
00757
00758
00759
00760
00761
00762 void Z_ClearZone( memzone_t *zone, int size ) {
00763 memblock_t *block;
00764
00765
00766
00767 zone->blocklist.next = zone->blocklist.prev = block =
00768 (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
00769 zone->blocklist.tag = 1;
00770 zone->blocklist.id = 0;
00771 zone->blocklist.size = 0;
00772 zone->rover = block;
00773 zone->size = size;
00774 zone->used = 0;
00775
00776 block->prev = block->next = &zone->blocklist;
00777 block->tag = 0;
00778 block->id = ZONEID;
00779 block->size = size - sizeof(memzone_t);
00780 }
00781
00782
00783
00784
00785
00786
00787 int Z_AvailableZoneMemory( memzone_t *zone ) {
00788 return zone->size - zone->used;
00789 }
00790
00791
00792
00793
00794
00795
00796 int Z_AvailableMemory( void ) {
00797 return Z_AvailableZoneMemory( mainzone );
00798 }
00799
00800
00801
00802
00803
00804
00805 void Z_Free( void *ptr ) {
00806 memblock_t *block, *other;
00807 memzone_t *zone;
00808
00809 if (!ptr) {
00810 Com_Error( ERR_DROP, "Z_Free: NULL pointer" );
00811 }
00812
00813 block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
00814 if (block->id != ZONEID) {
00815 Com_Error( ERR_FATAL, "Z_Free: freed a pointer without ZONEID" );
00816 }
00817 if (block->tag == 0) {
00818 Com_Error( ERR_FATAL, "Z_Free: freed a freed pointer" );
00819 }
00820
00821 if (block->tag == TAG_STATIC) {
00822 return;
00823 }
00824
00825
00826 if ( *(int *)((byte *)block + block->size - 4 ) != ZONEID ) {
00827 Com_Error( ERR_FATAL, "Z_Free: memory block wrote past end" );
00828 }
00829
00830 if (block->tag == TAG_SMALL) {
00831 zone = smallzone;
00832 }
00833 else {
00834 zone = mainzone;
00835 }
00836
00837 zone->used -= block->size;
00838
00839
00840 Com_Memset( ptr, 0xaa, block->size - sizeof( *block ) );
00841
00842 block->tag = 0;
00843
00844 other = block->prev;
00845 if (!other->tag) {
00846
00847 other->size += block->size;
00848 other->next = block->next;
00849 other->next->prev = other;
00850 if (block == zone->rover) {
00851 zone->rover = other;
00852 }
00853 block = other;
00854 }
00855
00856 zone->rover = block;
00857
00858 other = block->next;
00859 if ( !other->tag ) {
00860
00861 block->size += other->size;
00862 block->next = other->next;
00863 block->next->prev = block;
00864 if (other == zone->rover) {
00865 zone->rover = block;
00866 }
00867 }
00868 }
00869
00870
00871
00872
00873
00874
00875
00876 void Z_FreeTags( int tag ) {
00877 int count;
00878 memzone_t *zone;
00879
00880 if ( tag == TAG_SMALL ) {
00881 zone = smallzone;
00882 }
00883 else {
00884 zone = mainzone;
00885 }
00886 count = 0;
00887
00888
00889 zone->rover = zone->blocklist.next;
00890 do {
00891 if ( zone->rover->tag == tag ) {
00892 count++;
00893 Z_Free( (void *)(zone->rover + 1) );
00894 continue;
00895 }
00896 zone->rover = zone->rover->next;
00897 } while ( zone->rover != &zone->blocklist );
00898 }
00899
00900
00901
00902
00903
00904
00905
00906 #ifdef ZONE_DEBUG
00907 void *Z_TagMallocDebug( int size, int tag, char *label, char *file, int line ) {
00908 #else
00909 void *Z_TagMalloc( int size, int tag ) {
00910 #endif
00911 int extra, allocSize;
00912 memblock_t *start, *rover, *new, *base;
00913 memzone_t *zone;
00914
00915 if (!tag) {
00916 Com_Error( ERR_FATAL, "Z_TagMalloc: tried to use a 0 tag" );
00917 }
00918
00919 if ( tag == TAG_SMALL ) {
00920 zone = smallzone;
00921 }
00922 else {
00923 zone = mainzone;
00924 }
00925
00926 allocSize = size;
00927
00928
00929
00930
00931 size += sizeof(memblock_t);
00932 size += 4;
00933 size = (size + 3) & ~3;
00934
00935 base = rover = zone->rover;
00936 start = base->prev;
00937
00938 do {
00939 if (rover == start) {
00940 #ifdef ZONE_DEBUG
00941 Z_LogHeap();
00942 #endif
00943
00944 Com_Error( ERR_FATAL, "Z_Malloc: failed on allocation of %i bytes from the %s zone",
00945 size, zone == smallzone ? "small" : "main");
00946 return NULL;
00947 }
00948 if (rover->tag) {
00949 base = rover = rover->next;
00950 } else {
00951 rover = rover->next;
00952 }
00953 } while (base->tag || base->size < size);
00954
00955
00956
00957
00958 extra = base->size - size;
00959 if (extra > MINFRAGMENT) {
00960
00961 new = (memblock_t *) ((byte *)base + size );
00962 new->size = extra;
00963 new->tag = 0;
00964 new->prev = base;
00965 new->id = ZONEID;
00966 new->next = base->next;
00967 new->next->prev = new;
00968 base->next = new;
00969 base->size = size;
00970 }
00971
00972 base->tag = tag;
00973
00974 zone->rover = base->next;
00975 zone->used += base->size;
00976
00977 base->id = ZONEID;
00978
00979 #ifdef ZONE_DEBUG
00980 base->d.label = label;
00981 base->d.file = file;
00982 base->d.line = line;
00983 base->d.allocSize = allocSize;
00984 #endif
00985
00986
00987 *(int *)((byte *)base + base->size - 4) = ZONEID;
00988
00989 return (void *) ((byte *)base + sizeof(memblock_t));
00990 }
00991
00992
00993
00994
00995
00996
00997 #ifdef ZONE_DEBUG
00998 void *Z_MallocDebug( int size, char *label, char *file, int line ) {
00999 #else
01000 void *Z_Malloc( int size ) {
01001 #endif
01002 void *buf;
01003
01004
01005
01006 #ifdef ZONE_DEBUG
01007 buf = Z_TagMallocDebug( size, TAG_GENERAL, label, file, line );
01008 #else
01009 buf = Z_TagMalloc( size, TAG_GENERAL );
01010 #endif
01011 Com_Memset( buf, 0, size );
01012
01013 return buf;
01014 }
01015
01016 #ifdef ZONE_DEBUG
01017 void *S_MallocDebug( int size, char *label, char *file, int line ) {
01018 return Z_TagMallocDebug( size, TAG_SMALL, label, file, line );
01019 }
01020 #else
01021 void *S_Malloc( int size ) {
01022 return Z_TagMalloc( size, TAG_SMALL );
01023 }
01024 #endif
01025
01026
01027
01028
01029
01030
01031 void Z_CheckHeap( void ) {
01032 memblock_t *block;
01033
01034 for (block = mainzone->blocklist.next ; ; block = block->next) {
01035 if (block->next == &mainzone->blocklist) {
01036 break;
01037 }
01038 if ( (byte *)block + block->size != (byte *)block->next)
01039 Com_Error( ERR_FATAL, "Z_CheckHeap: block size does not touch the next block\n" );
01040 if ( block->next->prev != block) {
01041 Com_Error( ERR_FATAL, "Z_CheckHeap: next block doesn't have proper back link\n" );
01042 }
01043 if ( !block->tag && !block->next->tag ) {
01044 Com_Error( ERR_FATAL, "Z_CheckHeap: two consecutive free blocks\n" );
01045 }
01046 }
01047 }
01048
01049
01050
01051
01052
01053
01054 void Z_LogZoneHeap( memzone_t *zone, char *name ) {
01055 #ifdef ZONE_DEBUG
01056 char dump[32], *ptr;
01057 int i, j;
01058 #endif
01059 memblock_t *block;
01060 char buf[4096];
01061 int size, allocSize, numBlocks;
01062
01063 if (!logfile || !FS_Initialized())
01064 return;
01065 size = allocSize = numBlocks = 0;
01066 Com_sprintf(buf, sizeof(buf), "\r\n================\r\n%s log\r\n================\r\n", name);
01067 FS_Write(buf, strlen(buf), logfile);
01068 for (block = zone->blocklist.next ; block->next != &zone->blocklist; block = block->next) {
01069 if (block->tag) {
01070 #ifdef ZONE_DEBUG
01071 ptr = ((char *) block) + sizeof(memblock_t);
01072 j = 0;
01073 for (i = 0; i < 20 && i < block->d.allocSize; i++) {
01074 if (ptr[i] >= 32 && ptr[i] < 127) {
01075 dump[j++] = ptr[i];
01076 }
01077 else {
01078 dump[j++] = '_';
01079 }
01080 }
01081 dump[j] = '\0';
01082 Com_sprintf(buf, sizeof(buf), "size = %8d: %s, line: %d (%s) [%s]\r\n", block->d.allocSize, block->d.file, block->d.line, block->d.label, dump);
01083 FS_Write(buf, strlen(buf), logfile);
01084 allocSize += block->d.allocSize;
01085 #endif
01086 size += block->size;
01087 numBlocks++;
01088 }
01089 }
01090 #ifdef ZONE_DEBUG
01091
01092 size -= numBlocks * sizeof(zonedebug_t);
01093 #else
01094 allocSize = numBlocks * sizeof(memblock_t);
01095 #endif
01096 Com_sprintf(buf, sizeof(buf), "%d %s memory in %d blocks\r\n", size, name, numBlocks);
01097 FS_Write(buf, strlen(buf), logfile);
01098 Com_sprintf(buf, sizeof(buf), "%d %s memory overhead\r\n", size - allocSize, name);
01099 FS_Write(buf, strlen(buf), logfile);
01100 }
01101
01102
01103
01104
01105
01106
01107 void Z_LogHeap( void ) {
01108 Z_LogZoneHeap( mainzone, "MAIN" );
01109 Z_LogZoneHeap( smallzone, "SMALL" );
01110 }
01111
01112
01113 typedef struct memstatic_s {
01114 memblock_t b;
01115 byte mem[2];
01116 } memstatic_t;
01117
01118
01119 memstatic_t emptystring =
01120 { {(sizeof(memblock_t)+2 + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'\0', '\0'} };
01121 memstatic_t numberstring[] = {
01122 { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'0', '\0'} },
01123 { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'1', '\0'} },
01124 { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'2', '\0'} },
01125 { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'3', '\0'} },
01126 { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'4', '\0'} },
01127 { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'5', '\0'} },
01128 { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'6', '\0'} },
01129 { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'7', '\0'} },
01130 { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'8', '\0'} },
01131 { {(sizeof(memstatic_t) + 3) & ~3, TAG_STATIC, NULL, NULL, ZONEID}, {'9', '\0'} }
01132 };
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142 char *CopyString( const char *in ) {
01143 char *out;
01144
01145 if (!in[0]) {
01146 return ((char *)&emptystring) + sizeof(memblock_t);
01147 }
01148 else if (!in[1]) {
01149 if (in[0] >= '0' && in[0] <= '9') {
01150 return ((char *)&numberstring[in[0]-'0']) + sizeof(memblock_t);
01151 }
01152 }
01153 out = S_Malloc (strlen(in)+1);
01154 strcpy (out, in);
01155 return out;
01156 }
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193 #define HUNK_MAGIC 0x89537892
01194 #define HUNK_FREE_MAGIC 0x89537893
01195
01196 typedef struct {
01197 int magic;
01198 int size;
01199 } hunkHeader_t;
01200
01201 typedef struct {
01202 int mark;
01203 int permanent;
01204 int temp;
01205 int tempHighwater;
01206 } hunkUsed_t;
01207
01208 typedef struct hunkblock_s {
01209 int size;
01210 byte printed;
01211 struct hunkblock_s *next;
01212 char *label;
01213 char *file;
01214 int line;
01215 } hunkblock_t;
01216
01217 static hunkblock_t *hunkblocks;
01218
01219 static hunkUsed_t hunk_low, hunk_high;
01220 static hunkUsed_t *hunk_permanent, *hunk_temp;
01221
01222 static byte *s_hunkData = NULL;
01223 static int s_hunkTotal;
01224
01225 static int s_zoneTotal;
01226 static int s_smallZoneTotal;
01227
01228
01229
01230
01231
01232
01233
01234 void Com_Meminfo_f( void ) {
01235 memblock_t *block;
01236 int zoneBytes, zoneBlocks;
01237 int smallZoneBytes, smallZoneBlocks;
01238 int botlibBytes, rendererBytes;
01239 int unused;
01240
01241 zoneBytes = 0;
01242 botlibBytes = 0;
01243 rendererBytes = 0;
01244 zoneBlocks = 0;
01245 for (block = mainzone->blocklist.next ; ; block = block->next) {
01246 if ( Cmd_Argc() != 1 ) {
01247 Com_Printf ("block:%p size:%7i tag:%3i\n",
01248 block, block->size, block->tag);
01249 }
01250 if ( block->tag ) {
01251 zoneBytes += block->size;
01252 zoneBlocks++;
01253 if ( block->tag == TAG_BOTLIB ) {
01254 botlibBytes += block->size;
01255 } else if ( block->tag == TAG_RENDERER ) {
01256 rendererBytes += block->size;
01257 }
01258 }
01259
01260 if (block->next == &mainzone->blocklist) {
01261 break;
01262 }
01263 if ( (byte *)block + block->size != (byte *)block->next) {
01264 Com_Printf ("ERROR: block size does not touch the next block\n");
01265 }
01266 if ( block->next->prev != block) {
01267 Com_Printf ("ERROR: next block doesn't have proper back link\n");
01268 }
01269 if ( !block->tag && !block->next->tag ) {
01270 Com_Printf ("ERROR: two consecutive free blocks\n");
01271 }
01272 }
01273
01274 smallZoneBytes = 0;
01275 smallZoneBlocks = 0;
01276 for (block = smallzone->blocklist.next ; ; block = block->next) {
01277 if ( block->tag ) {
01278 smallZoneBytes += block->size;
01279 smallZoneBlocks++;
01280 }
01281
01282 if (block->next == &smallzone->blocklist) {
01283 break;
01284 }
01285 }
01286
01287 Com_Printf( "%8i bytes total hunk\n", s_hunkTotal );
01288 Com_Printf( "%8i bytes total zone\n", s_zoneTotal );
01289 Com_Printf( "\n" );
01290 Com_Printf( "%8i low mark\n", hunk_low.mark );
01291 Com_Printf( "%8i low permanent\n", hunk_low.permanent );
01292 if ( hunk_low.temp != hunk_low.permanent ) {
01293 Com_Printf( "%8i low temp\n", hunk_low.temp );
01294 }
01295 Com_Printf( "%8i low tempHighwater\n", hunk_low.tempHighwater );
01296 Com_Printf( "\n" );
01297 Com_Printf( "%8i high mark\n", hunk_high.mark );
01298 Com_Printf( "%8i high permanent\n", hunk_high.permanent );
01299 if ( hunk_high.temp != hunk_high.permanent ) {
01300 Com_Printf( "%8i high temp\n", hunk_high.temp );
01301 }
01302 Com_Printf( "%8i high tempHighwater\n", hunk_high.tempHighwater );
01303 Com_Printf( "\n" );
01304 Com_Printf( "%8i total hunk in use\n", hunk_low.permanent + hunk_high.permanent );
01305 unused = 0;
01306 if ( hunk_low.tempHighwater > hunk_low.permanent ) {
01307 unused += hunk_low.tempHighwater - hunk_low.permanent;
01308 }
01309 if ( hunk_high.tempHighwater > hunk_high.permanent ) {
01310 unused += hunk_high.tempHighwater - hunk_high.permanent;
01311 }
01312 Com_Printf( "%8i unused highwater\n", unused );
01313 Com_Printf( "\n" );
01314 Com_Printf( "%8i bytes in %i zone blocks\n", zoneBytes, zoneBlocks );
01315 Com_Printf( " %8i bytes in dynamic botlib\n", botlibBytes );
01316 Com_Printf( " %8i bytes in dynamic renderer\n", rendererBytes );
01317 Com_Printf( " %8i bytes in dynamic other\n", zoneBytes - ( botlibBytes + rendererBytes ) );
01318 Com_Printf( " %8i bytes in small Zone memory\n", smallZoneBytes );
01319 }
01320
01321
01322
01323
01324
01325
01326
01327
01328 void Com_TouchMemory( void ) {
01329 int start, end;
01330 int i, j;
01331 int sum;
01332 memblock_t *block;
01333
01334 Z_CheckHeap();
01335
01336 start = Sys_Milliseconds();
01337
01338 sum = 0;
01339
01340 j = hunk_low.permanent >> 2;
01341 for ( i = 0 ; i < j ; i+=64 ) {
01342 sum += ((int *)s_hunkData)[i];
01343 }
01344
01345 i = ( s_hunkTotal - hunk_high.permanent ) >> 2;
01346 j = hunk_high.permanent >> 2;
01347 for ( ; i < j ; i+=64 ) {
01348 sum += ((int *)s_hunkData)[i];
01349 }
01350
01351 for (block = mainzone->blocklist.next ; ; block = block->next) {
01352 if ( block->tag ) {
01353 j = block->size >> 2;
01354 for ( i = 0 ; i < j ; i+=64 ) {
01355 sum += ((int *)block)[i];
01356 }
01357 }
01358 if ( block->next == &mainzone->blocklist ) {
01359 break;
01360 }
01361 }
01362
01363 end = Sys_Milliseconds();
01364
01365 Com_Printf( "Com_TouchMemory: %i msec\n", end - start );
01366 }
01367
01368
01369
01370
01371
01372
01373
01374
01375 void Com_InitSmallZoneMemory( void ) {
01376 s_smallZoneTotal = 512 * 1024;
01377
01378 smallzone = calloc( s_smallZoneTotal, 1 );
01379 if ( !smallzone ) {
01380 Com_Error( ERR_FATAL, "Small zone data failed to allocate %1.1f megs", (float)s_smallZoneTotal / (1024*1024) );
01381 }
01382 Z_ClearZone( smallzone, s_smallZoneTotal );
01383
01384