|
Atrinik Server 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00061 #include <global.h> 00062 00063 #ifdef MEMPOOL_OBJECT_TRACKING 00064 /* for debugging only! */ 00065 static struct mempool_chunk *used_object_list = NULL; 00066 static uint32 chunk_tracking_id = 1; 00067 #define MEMPOOL_OBJECT_FLAG_FREE 1 00068 #define MEMPOOL_OBJECT_FLAG_USED 2 00069 #endif 00070 00075 struct mempool_chunk end_marker; 00076 00077 int nrof_mempools = 0; 00078 struct mempool *mempools[MAX_NROF_MEMPOOLS]; 00079 00080 #ifdef MEMPOOL_TRACKING 00081 struct mempool *pool_puddle; 00082 #endif 00083 00084 struct mempool *pool_object, *pool_objectlink, *pool_player, *pool_bans, *pool_parties; 00085 00089 uint32 nearest_pow_two_exp(uint32 n) 00090 { 00091 static const uint32 exp_lookup[65] = 00092 { 00093 0, 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 00094 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 00095 }; 00096 uint32 i; 00097 00098 if (n <= 64) 00099 { 00100 return exp_lookup[n]; 00101 } 00102 00103 for (i = 7; (uint32) (1 << i) < n; i++) 00104 { 00105 } 00106 00107 return i; 00108 } 00109 00116 void setup_poolfunctions(struct mempool *pool, chunk_constructor constructor, chunk_destructor destructor) 00117 { 00118 pool->constructor = constructor; 00119 pool->destructor = destructor; 00120 } 00121 00133 struct mempool *create_mempool(const char *description, uint32 expand, uint32 size, uint32 flags, chunk_initialisator initialisator, chunk_deinitialisator deinitialisator, chunk_constructor constructor, chunk_destructor destructor) 00134 { 00135 int i; 00136 struct mempool *pool; 00137 00138 if (nrof_mempools >= MAX_NROF_MEMPOOLS) 00139 { 00140 LOG(llevError, "Too many memory pools registered. Please increase the MAX_NROF_MEMPOOLS constant in mempools.h\n"); 00141 } 00142 00143 pool = calloc(1, sizeof(struct mempool)); 00144 00145 mempools[nrof_mempools] = pool; 00146 00147 pool->chunk_description = description; 00148 pool->expand_size = expand; 00149 pool->chunksize = size; 00150 pool->flags = flags; 00151 pool->initialisator = initialisator; 00152 pool->deinitialisator = deinitialisator; 00153 pool->constructor = constructor; 00154 pool->destructor = destructor; 00155 00156 #if MEMORY_DEBUG 00157 pool->flags |= MEMPOOL_BYPASS_POOLS; 00158 #endif 00159 00160 for (i = 0; i < MEMPOOL_NROF_FREELISTS; i++) 00161 { 00162 pool->freelist[i] = &end_marker; 00163 pool->nrof_free[i] = 0; 00164 pool->nrof_allocated[i] = 0; 00165 } 00166 00167 #ifdef MEMPOOL_TRACKING 00168 pool->first_puddle_info = NULL; 00169 #endif 00170 00171 nrof_mempools++; 00172 00173 return pool; 00174 } 00175 00178 void init_mempools() 00179 { 00180 #ifdef MEMPOOL_TRACKING 00181 pool_puddle = create_mempool("puddles", 10, sizeof(struct puddle_info), MEMPOOL_ALLOW_FREEING, NULL, NULL, NULL, NULL); 00182 #endif 00183 pool_object = create_mempool("objects", OBJECT_EXPAND, sizeof(object), 0, NULL, NULL, (chunk_constructor) initialize_object, (chunk_destructor) destroy_object); 00184 pool_player = create_mempool("players", 25, sizeof(player), MEMPOOL_BYPASS_POOLS, NULL, NULL, NULL, NULL); 00185 pool_objectlink = create_mempool("object links", 500, sizeof(objectlink), 0, NULL, NULL, NULL, NULL); 00186 pool_bans = create_mempool("bans", 25, sizeof(_ban_struct), 0, NULL, NULL, NULL, NULL); 00187 pool_parties = create_mempool("parties", 25, sizeof(party_struct), 0, NULL, NULL, NULL, NULL); 00188 00189 /* Initialize end-of-list pointers and a few other values*/ 00190 removed_objects = &end_marker; 00191 00192 /* Set up container for "loose" objects */ 00193 initialize_object(&void_container); 00194 void_container.type = VOID_CONTAINER; 00195 FREE_AND_COPY_HASH(void_container.name, "<void container>"); 00196 } 00197 00201 static void free_mempool(struct mempool *pool) 00202 { 00203 free(pool); 00204 } 00205 00208 void free_mempools() 00209 { 00210 LOG(llevDebug, "Freeing memory pools.\n"); 00211 #ifdef MEMPOOL_TRACKING 00212 free_mempool(pool_puddle); 00213 #endif 00214 free_mempool(pool_object); 00215 free_mempool(pool_player); 00216 free_mempool(pool_objectlink); 00217 free_mempool(pool_bans); 00218 free_mempool(pool_parties); 00219 00220 FREE_AND_CLEAR_HASH2(void_container.name); 00221 } 00222 00230 static void expand_mempool(struct mempool *pool, uint32 arraysize_exp) 00231 { 00232 uint32 i; 00233 struct mempool_chunk *first, *ptr; 00234 int chunksize_real, nrof_arrays; 00235 00236 if (pool->nrof_free[arraysize_exp] > 0) 00237 { 00238 LOG(llevBug, "expand_mempool() called with chunks still available in pool\n"); 00239 } 00240 00241 nrof_arrays = pool->expand_size >> arraysize_exp; 00242 00243 if (nrof_arrays == 0) 00244 { 00245 LOG(llevDebug, "expand_mempool() called with too big array size for its expand_size\n"); 00246 nrof_arrays = 1; 00247 } 00248 00249 chunksize_real = sizeof(struct mempool_chunk) + (pool->chunksize << arraysize_exp); 00250 first = (struct mempool_chunk *) calloc(1, nrof_arrays * chunksize_real); 00251 00252 if (first == NULL) 00253 { 00254 LOG(llevError, "expand_mempool(): Out of memory.\n"); 00255 } 00256 00257 pool->freelist[arraysize_exp] = first; 00258 pool->nrof_allocated[arraysize_exp] += nrof_arrays; 00259 pool->nrof_free[arraysize_exp] = nrof_arrays; 00260 00261 /* Set up the linked list */ 00262 ptr = first; 00263 00264 for (i = 0; (int) i < nrof_arrays - 1; i++) 00265 { 00266 #ifdef DEBUG_MEMPOOL_OBJECT_TRACKING 00267 ptr->obj_next = ptr->obj_prev = 0; 00268 ptr->pool = pool; 00269 /* This is a real, unique object ID. Allows tracking beyond 00270 * get/free objects */ 00271 ptr->id = chunk_tracking_id++; 00272 ptr->flags |= MEMPOOL_OBJECT_FLAG_FREE; 00273 #endif 00274 if (pool->initialisator) 00275 { 00276 pool->initialisator(MEM_USERDATA(ptr)); 00277 } 00278 00279 ptr = ptr->next = (struct mempool_chunk *) (((char *) ptr) + chunksize_real); 00280 } 00281 00282 /* And the last element */ 00283 ptr->next = &end_marker; 00284 00285 if (pool->initialisator) 00286 { 00287 pool->initialisator(MEM_USERDATA(ptr)); 00288 } 00289 00290 #ifdef DEBUG_MEMPOOL_OBJECT_TRACKING 00291 ptr->obj_next = ptr->obj_prev = 0; /* secure */ 00292 ptr->pool = pool; 00293 /* This is a real, unique object ID. Allows tracking beyond get/free 00294 * objects */ 00295 ptr->id = chunk_tracking_id++; 00296 ptr->flags |= MEMPOOL_OBJECT_FLAG_FREE; 00297 #endif 00298 00299 #ifdef MEMPOOL_TRACKING 00300 /* Track the allocation of puddles */ 00301 { 00302 struct puddle_info *p = get_poolchunk(pool_puddle); 00303 p->first_chunk = first; 00304 p->next = pool->first_puddle_info; 00305 pool->first_puddle_info = p; 00306 } 00307 #endif 00308 } 00309 00316 void *get_poolchunk_array_real(struct mempool *pool, uint32 arraysize_exp) 00317 { 00318 struct mempool_chunk *new_obj; 00319 00320 if (pool->flags & MEMPOOL_BYPASS_POOLS) 00321 { 00322 new_obj = calloc(1, sizeof(struct mempool_chunk) + (pool->chunksize << arraysize_exp)); 00323 pool->nrof_allocated[arraysize_exp]++; 00324 } 00325 else 00326 { 00327 if (pool->nrof_free[arraysize_exp] == 0) 00328 { 00329 expand_mempool(pool, arraysize_exp); 00330 } 00331 00332 new_obj = pool->freelist[arraysize_exp]; 00333 pool->freelist[arraysize_exp] = new_obj->next; 00334 pool->nrof_free[arraysize_exp]--; 00335 } 00336 00337 new_obj->next = NULL; 00338 00339 if (pool->constructor) 00340 { 00341 pool->constructor(MEM_USERDATA(new_obj)); 00342 } 00343 00344 #ifdef DEBUG_MEMPOOL_OBJECT_TRACKING 00345 if (new_obj->obj_prev || new_obj->obj_next) 00346 { 00347 LOG(llevDebug, "get_poolchunk_array_real() object >%d< is in used_object list!!\n", new_obj->id); 00348 } 00349 00350 /* Put it in front of the used object list */ 00351 new_obj->obj_next = used_object_list; 00352 00353 if (new_obj->obj_next) 00354 { 00355 new_obj->obj_next->obj_prev = new_obj; 00356 } 00357 00358 used_object_list = new_obj; 00359 new_obj->flags &= ~MEMPOOL_OBJECT_FLAG_FREE; 00360 new_obj->flags |= MEMPOOL_OBJECT_FLAG_USED; 00361 #endif 00362 00363 return MEM_USERDATA(new_obj); 00364 } 00365 00374 void return_poolchunk_array_real(void *data, uint32 arraysize_exp, struct mempool *pool) 00375 { 00376 struct mempool_chunk *old = MEM_POOLDATA(data); 00377 00378 if (CHUNK_FREE(data)) 00379 { 00380 LOG(llevBug, "return_poolchunk_array_real() on already free chunk (pool \"%s\")\n", pool->chunk_description); 00381 return; 00382 } 00383 00384 #ifdef DEBUG_MEMPOOL_OBJECT_TRACKING 00385 if (old->obj_next) 00386 { 00387 old->obj_next->obj_prev = old->obj_prev; 00388 } 00389 00390 if (old->obj_prev) 00391 { 00392 old->obj_prev->obj_next = old->obj_next; 00393 } 00394 else 00395 { 00396 used_object_list = old->obj_next; 00397 } 00398 00399 old->obj_next = old->obj_prev = 0; 00400 old->flags &= ~MEMPOOL_OBJECT_FLAG_USED; 00401 old->flags |= MEMPOOL_OBJECT_FLAG_FREE; 00402 #endif 00403 00404 if (pool->destructor) 00405 { 00406 pool->destructor(data); 00407 } 00408 00409 if (pool->flags & MEMPOOL_BYPASS_POOLS) 00410 { 00411 if (pool->deinitialisator) 00412 { 00413 pool->deinitialisator(MEM_USERDATA(old)); 00414 } 00415 00416 free(old); 00417 pool->nrof_allocated[arraysize_exp]--; 00418 } 00419 else 00420 { 00421 old->next = pool->freelist[arraysize_exp]; 00422 pool->freelist[arraysize_exp] = old; 00423 pool->nrof_free[arraysize_exp]++; 00424 } 00425 } 00426 00435 void dump_mempool_statistics(object *op, int *sum_used, int *sum_alloc) 00436 { 00437 int j, k; 00438 char buf[MAX_BUF]; 00439 00440 for (j = 0; j < nrof_mempools; j++) 00441 { 00442 for (k = 0; k < MEMPOOL_NROF_FREELISTS; k++) 00443 { 00444 if (mempools[j]->nrof_allocated[k] > 0) 00445 { 00446 int ob_used = mempools[j]->nrof_allocated[k] - mempools[j]-> nrof_free[k], ob_free = mempools[j]->nrof_free[k]; 00447 int mem_used = ob_used * ((mempools[j]->chunksize << k) + sizeof(struct mempool_chunk)); 00448 int mem_free = ob_free * ((mempools[j]->chunksize << k) + sizeof(struct mempool_chunk)); 00449 00450 snprintf(buf, sizeof(buf), "%4d used (%4d free) %s[%3d]: %d (%d)", ob_used, ob_free, mempools[j]->chunk_description, 1 << k, mem_used, mem_free); 00451 00452 if (op) 00453 { 00454 new_draw_info(0, COLOR_WHITE, op, buf); 00455 } 00456 00457 LOG(llevSystem, "%s\n", buf); 00458 00459 if (sum_used) 00460 { 00461 *sum_used += mem_used; 00462 } 00463 00464 if (sum_alloc) 00465 { 00466 *sum_alloc += mem_used + mem_free; 00467 } 00468 } 00469 } 00470 } 00471 } 00472 00473 #ifdef DEBUG_MEMPOOL_OBJECT_TRACKING 00474 00481 void check_use_object_list() 00482 { 00483 struct mempool_chunk *chunk; 00484 00485 for (chunk = used_object_list; chunk; chunk = chunk->obj_next) 00486 { 00487 #ifdef MEMPOOL_TRACKING 00488 /* ignore for now */ 00489 if (chunk->pool == pool_puddle) 00490 { 00491 } 00492 else 00493 #endif 00494 if (chunk->pool == pool_object) 00495 { 00496 object *tmp2, *tmp = MEM_USERDATA(chunk); 00497 00498 if (QUERY_FLAG(tmp, FLAG_REMOVED)) 00499 { 00500 LOG(llevDebug, "check_use_object_list(): object >%s< (%d) has removed flag set!\n", query_name(tmp), chunk->id); 00501 } 00502 00503 /* We are on a map */ 00504 if (tmp->map) 00505 { 00506 if (tmp->map->in_memory != MAP_IN_MEMORY) 00507 { 00508 LOG(llevDebug, "check_use_object_list(): object >%s< (%d) has invalid map! >%d<!\n", query_name(tmp), tmp->map->name ? tmp->map->name : "NONE", chunk->id); 00509 } 00510 else 00511 { 00512 for (tmp2 = get_map_ob(tmp->map, tmp->x, tmp->y); tmp2; tmp2 = tmp2->above) 00513 { 00514 if (tmp2 == tmp) 00515 { 00516 goto goto_object_found; 00517 } 00518 } 00519 00520 LOG(llevDebug, "check_use_object_list(): object >%s< (%d) has invalid map! >%d<!\n", query_name(tmp), tmp->map->name ? tmp->map->name : "NONE", chunk->id); 00521 } 00522 } 00523 else if (tmp->env) 00524 { 00525 /* Object claims to be here... Let's check it IS here */ 00526 for (tmp2 = tmp->env->inv; tmp2; tmp2 = tmp2->below) 00527 { 00528 if (tmp2 == tmp) 00529 { 00530 goto goto_object_found; 00531 } 00532 } 00533 00534 LOG(llevDebug, "check_use_object_list(): object >%s< (%d) has invalid env >%d<!\n", query_name(tmp), query_name(tmp->env), chunk->id); 00535 } 00536 /* Where are we? */ 00537 else 00538 { 00539 LOG(llevDebug, "check_use_object_list(): object >%s< (%d) has no env/map\n", query_name(tmp), chunk->id); 00540 } 00541 } 00542 else if (chunk->pool == pool_player) 00543 { 00544 player *tmp = MEM_USERDATA(chunk); 00545 } 00546 else 00547 { 00548 LOG(llevDebug, "check_use_object_list(): wrong pool ID! (%s - %d)", chunk->pool->chunk_description, chunk->id); 00549 } 00550 00551 goto_object_found:; 00552 } 00553 } 00554 #endif
1.7.4