static void sweep_pinned_objects_callback (char *ptr, size_t size, void *data) { if (SGEN_OBJECT_IS_PINNED (ptr)) { SGEN_UNPIN_OBJECT (ptr); DEBUG (6, fprintf (gc_debug_file, "Unmarked pinned object %p (%s)\n", ptr, safe_name (ptr))); } else { DEBUG (6, fprintf (gc_debug_file, "Freeing unmarked pinned object %p (%s)\n", ptr, safe_name (ptr))); free_pinned_object (ptr, size); } }
/* LOCKING: requires that the GC lock is held */ static void collect_bridge_objects (CopyOrMarkObjectFunc copy_func, char *start, char *end, int generation, GrayQueue *queue) { SgenHashTable *hash_table = get_finalize_entry_hash_table (generation); MonoObject *object; gpointer dummy; char *copy; if (no_finalize) return; SGEN_HASH_TABLE_FOREACH (hash_table, object, dummy) { int tag = tagged_object_get_tag (object); object = tagged_object_get_object (object); /* Bridge code told us to ignore this one */ if (tag == BRIDGE_OBJECT_MARKED) continue; /* Object is a bridge object and major heap says it's dead */ if (!((char*)object >= start && (char*)object < end && !major_collector.is_object_live ((char*)object))) continue; /* Nursery says the object is dead. */ if (!object_is_fin_ready (object)) continue; if (!mono_sgen_is_bridge_object (object)) continue; copy = (char*)object; copy_func ((void**)©, queue); mono_sgen_bridge_register_finalized_object ((MonoObject*)copy); if (hash_table == &minor_finalizable_hash && !ptr_in_nursery (copy)) { /* remove from the list */ SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE); /* insert it into the major hash */ mono_sgen_hash_table_replace (&major_finalizable_hash, tagged_object_apply (copy, tag), NULL); DEBUG (5, fprintf (gc_debug_file, "Promoting finalization of object %p (%s) (was at %p) to major table\n", copy, safe_name (copy), object)); continue; } else { /* update pointer */ DEBUG (5, fprintf (gc_debug_file, "Updating object for finalization: %p (%s) (was at %p)\n", copy, safe_name (copy), object)); SGEN_HASH_TABLE_FOREACH_SET_KEY (tagged_object_apply (copy, tag)); } } SGEN_HASH_TABLE_FOREACH_END;
static void unparse_boolexp1( dbref player, BOOLEXP *b, char outer_type, int format ) { ATTR *ap; char sep_ch; char *buff; if( b == TRUE_BOOLEXP ) { if( format == F_EXAMINE ) { safe_str( ( char * ) "*UNLOCKED*", boolexp_buf, &buftop ); } return; } switch( b->type ) { case BOOLEXP_AND: if( outer_type == BOOLEXP_NOT ) { safe_chr( '(', boolexp_buf, &buftop ); } unparse_boolexp1( player, b->sub1, b->type, format ); safe_chr( AND_TOKEN, boolexp_buf, &buftop ); unparse_boolexp1( player, b->sub2, b->type, format ); if( outer_type == BOOLEXP_NOT ) { safe_chr( ')', boolexp_buf, &buftop ); } break; case BOOLEXP_OR: if( outer_type == BOOLEXP_NOT || outer_type == BOOLEXP_AND ) { safe_chr( '(', boolexp_buf, &buftop ); } unparse_boolexp1( player, b->sub1, b->type, format ); safe_chr( OR_TOKEN, boolexp_buf, &buftop ); unparse_boolexp1( player, b->sub2, b->type, format ); if( outer_type == BOOLEXP_NOT || outer_type == BOOLEXP_AND ) { safe_chr( ')', boolexp_buf, &buftop ); } break; case BOOLEXP_NOT: safe_chr( '!', boolexp_buf, &buftop ); unparse_boolexp1( player, b->sub1, b->type, format ); break; case BOOLEXP_INDIR: safe_chr( INDIR_TOKEN, boolexp_buf, &buftop ); unparse_boolexp1( player, b->sub1, b->type, format ); break; case BOOLEXP_IS: safe_chr( IS_TOKEN, boolexp_buf, &buftop ); unparse_boolexp1( player, b->sub1, b->type, format ); break; case BOOLEXP_CARRY: safe_chr( CARRY_TOKEN, boolexp_buf, &buftop ); unparse_boolexp1( player, b->sub1, b->type, format ); break; case BOOLEXP_OWNER: safe_chr( OWNER_TOKEN, boolexp_buf, &buftop ); unparse_boolexp1( player, b->sub1, b->type, format ); break; case BOOLEXP_CONST: if( !mudstate.standalone ) { switch( format ) { case F_QUIET: /* * Quiet output - for dumps and internal use. * Always #Num */ safe_str( ( char * ) unparse_object_quiet( player, b->thing ), boolexp_buf, &buftop ); break; case F_EXAMINE: /* * Examine output - informative. * * Name(#Num) or Name */ buff = unparse_object( player, b->thing, 0 ); safe_str( buff, boolexp_buf, &buftop ); free_lbuf( buff ); break; case F_DECOMPILE: /* * Decompile output - should be usable on * other MUSHes. *Name if player, Name if * thing, else #Num */ switch( Typeof( b->thing ) ) { case TYPE_PLAYER: safe_chr( '*', boolexp_buf, &buftop ); case TYPE_THING: safe_name( b->thing, boolexp_buf, &buftop ); break; default: safe_dbref( boolexp_buf, &buftop, b->thing ); break; } break; case F_FUNCTION: /* * Function output - must be usable by @lock * cmd. *Name if player, else #Num */ switch( Typeof( b->thing ) ) { case TYPE_PLAYER: safe_chr( '*', boolexp_buf, &buftop ); safe_name( b->thing, boolexp_buf, &buftop ); break; default: safe_dbref( boolexp_buf, &buftop, b->thing ); break; } } } else { safe_str( ( char * ) unparse_object_quiet( player, b->thing ), boolexp_buf, &buftop ); } break; case BOOLEXP_ATR: case BOOLEXP_EVAL: if( b->type == BOOLEXP_EVAL ) { sep_ch = '/'; } else { sep_ch = ':'; } ap = atr_num( b->thing ); if( ap && ap->number ) { safe_str( ( char * ) ap->name, boolexp_buf, &buftop ); } else { safe_ltos( boolexp_buf, &buftop, b->thing ); } safe_chr( sep_ch, boolexp_buf, &buftop ); safe_str( ( char * ) b->sub1, boolexp_buf, &buftop ); break; default: log_write_raw( 1, "ABORT! unparse.c, bad boolexp type in unparse_boolexp1().\n" ); abort(); break; } }
int creature_init(struct t_creature* o_entity, struct t_creature_generate_rules* genrules) { memset(o_entity,0,sizeof(struct t_creature)); if ((genrules == NULL) || (genrules->gender = EG_RANDOM) || !vrange(&genrules->age)) { random_gender_and_age(&o_entity->age, &o_entity->gender_id); } else { if ((genrules) || vrange(&genrules->age)) { o_entity->age = randrange(&genrules->age); } else o_entity->age = 18 + randval(40); enum entity_gender g_gender = genrules ? genrules->gender : EG_RANDOM; switch (g_gender) { case EG_MALE: o_entity->gender_id = EG_MALE; break; case EG_FEMALE: o_entity->gender_id = EG_FEMALE; break; case EG_WMPATRIARCH: o_entity->gender_id = EG_WMPATRIARCH; break; //will be replaced with male after the name is generated. case EG_NEUTRAL: o_entity->gender_id = EG_NEUTRAL; o_entity->gender_bio = randbetween(EG_MALE,EG_FEMALE); break; case EG_MBIAS: o_entity->gender_id = (randval(100) < 75) ? EG_MALE : EG_FEMALE; break; case EG_FBIAS: o_entity->gender_id = (randval(100) < 75) ? EG_MALE : EG_FEMALE; break; case EG_RANDOM: default: o_entity->gender_id = (randval(100) < 52) ? EG_FEMALE : EG_MALE; break; //52% females according to U.S. Census data } } if ((randval(100) < 1) && (o_entity->gender_bio == EG_RANDOM)) o_entity->gender_bio = randbetween(EG_NEUTRAL,EG_FEMALE); else o_entity->gender_bio = o_entity->gender_id; //will result in mismatches for 0.67% of cases. o_entity->birthday_month = randval(12) + 1; switch(o_entity->birthday_month) { case 4: case 6: case 9: case 11: o_entity->birthday_day=randval(30)+1; break; case 2: o_entity->birthday_day=randval(28)+1; break; default: o_entity->birthday_day=randval(31)+1; break; } o_entity->id=curcreatureid++; for(int w=0;w<EB_COUNT;w++)o_entity->wound[w]=0; for(int a=0;a<EA_COUNT;a++)o_entity->attributes[a]=1; int attnum=32; if (genrules) { o_entity->type = genrules->type; for (int i=0; i < RANDATTRS; i++) if (vrange(&genrules->attrlim[i])) o_entity->attributes[genrules->attrs[i]] = randrange(&genrules->attrlim[i]); for (int i=0; i < RANDSKILLS; i++) if (vrange(&genrules->skilllim[i])) o_entity->skills[genrules->skill[i]] = randrange(&genrules->skilllim[i]); enum Alignment align = genrules->align; if (genrules->random_align) align += randbetween(-2,2); if (align < ALIGN_ARCHCONSERVATIVE) align = ALIGN_ARCHCONSERVATIVE; if (align > ALIGN_ELITELIBERAL) align = ALIGN_ELITELIBERAL; o_entity->align = align; o_entity->orig_align = align; if (vrange(&genrules->juice)) o_entity->juice = randrange(&genrules->juice); if (vrange(&genrules->money)) o_entity->money = randrange(&genrules->money); for (int i=0; i < RANDATTRS; i++) if (vrange(&genrules->attrlim[i])) o_entity->attributes[genrules->attrs[i]] = randrange(&genrules->attrlim[i]); for (int i=0; i < RANDSKILLS; i++) if (vrange(&genrules->skilllim[i])) o_entity->skills[genrules->skill[i]] = randrange(&genrules->skilllim[i]); if (vrange(&genrules->attrpts)) attnum = randrange(&genrules->attrpts); } while(attnum>0) { int a=randval(EA_COUNT); if(o_entity->attributes[a]<10) { o_entity->attributes[a]++; attnum--; } } //at this point, both the entity's alignment and gender are fixed. //let's generate a name. random_first_name(o_entity->firstname,o_entity->gender_id); random_last_name(o_entity->lastname,o_entity->align == ALIGN_ARCHCONSERVATIVE,o_entity->gender_id); int wi=0; int wn=0; while ((wi < RANDWEAPONS) && (genrules->weapons[wi])) { wn++; wi++; } if (wn) { wi = randval(wn); struct t_item new_weapon = {.type = IT_WEAPON, .itemtypeid = genrules->weapons[wi], .ammo = 200}; struct t_item clips = {.type = IT_CLIP, .itemtypeid = weapontypes[genrules->weapons[wi]].attacks[0].ammotype, .ammo = cliptypes[weapontypes[genrules->weapons[wi]].attacks[0].ammotype].ammo }; struct t_item* added_weapon = inv_add(o_entity->inventory, &new_weapon); o_entity->weapon = added_weapon; } o_entity->special[ESW_TEETH]=TOOTHNUM; o_entity->special[ESW_RIGHTEYE]=1; o_entity->special[ESW_LEFTEYE]=1; o_entity->special[ESW_NOSE]=1; o_entity->special[ESW_TONGUE]=1; o_entity->special[ESW_RIGHTLUNG]=1; o_entity->special[ESW_LEFTLUNG]=1; o_entity->special[ESW_HEART]=1; o_entity->special[ESW_LIVER]=1; o_entity->special[ESW_STOMACH]=1; o_entity->special[ESW_RIGHTKIDNEY]=1; o_entity->special[ESW_LEFTKIDNEY]=1; o_entity->special[ESW_SPLEEN]=1; o_entity->special[ESW_RIBS]=RIBNUM; o_entity->special[ESW_NECK]=1; o_entity->special[ESW_UPPERSPINE]=1; o_entity->special[ESW_LOWERSPINE]=1; o_entity->blood = 100; o_entity->alive = true; o_entity->exists = true; return 0; } int entity_name(struct t_creature* who) { random_first_name(who->firstname,who->gender_id); random_last_name(who->lastname,who->align == ALIGN_ARCHCONSERVATIVE,who->gender_id); return 0; } char* entityattrstr[EA_COUNT] = { "STR", "INT", "WIS", "AGI", "CON", "CHA", "HRT" }; const char* safe_name(const char* nameptr) { if ((nameptr == NULL) || (strlen(nameptr) == 0)) return "???"; return nameptr; } int describe_entity(struct t_creature* me, char* const restrict o_name, size_t strsize) { if (me != NULL) { if (strlen(me->nickname) != 0) { strncpy(o_name,me->nickname,strsize); return 0;} if (((strlen(me->firstname) != 0) || (strlen(me->firstname) != 0)) && (me->name_known)) { char fullname[66]; strncpy(fullname,safe_name(me->firstname),32); strncat(fullname," ",1); strncat(fullname,safe_name(me->lastname),32); strncpy(o_name,fullname,strsize); return 0; } const char* td = type_description(me); if (td) { strncpy(o_name,type_description(me),strsize); return 0; } } strncpy(o_name, "*",32); return 0; } char temp_name[16][128]; int temp_name_i = 0; const char* describe_entity_static(struct t_creature* me) { int r = describe_entity(me,temp_name[temp_name_i],128); const char* ret = (r == 0 ? temp_name[temp_name_i] : NULL); temp_name_i = (temp_name_i+1) % 16; return ret; }
/* LOCKING: requires that the GC lock is held */ static void finalize_in_range (CopyOrMarkObjectFunc copy_func, char *start, char *end, int generation, GrayQueue *queue) { FinalizeEntryHashTable *hash_table = get_finalize_entry_hash_table (generation); FinalizeEntry *entry, *prev; int i; FinalizeEntry **finalizable_hash = hash_table->table; mword finalizable_hash_size = hash_table->size; if (no_finalize) return; for (i = 0; i < finalizable_hash_size; ++i) { prev = NULL; for (entry = finalizable_hash [i]; entry;) { if ((char*)entry->object >= start && (char*)entry->object < end && !major_collector.is_object_live (entry->object)) { gboolean is_fin_ready = object_is_fin_ready (entry->object); char *copy = entry->object; copy_func ((void**)©, queue); if (is_fin_ready) { char *from; FinalizeEntry *next; /* remove and put in fin_ready_list */ if (prev) prev->next = entry->next; else finalizable_hash [i] = entry->next; next = entry->next; num_ready_finalizers++; hash_table->num_registered--; queue_finalization_entry (entry); bridge_register_finalized_object ((MonoObject*)copy); /* Make it survive */ from = entry->object; entry->object = copy; DEBUG (5, fprintf (gc_debug_file, "Queueing object for finalization: %p (%s) (was at %p) (%d/%d)\n", entry->object, safe_name (entry->object), from, num_ready_finalizers, hash_table->num_registered)); entry = next; continue; } else { char *from = entry->object; if (hash_table == &minor_finalizable_hash && !ptr_in_nursery (copy)) { FinalizeEntry *next = entry->next; unsigned int major_hash; /* remove from the list */ if (prev) prev->next = entry->next; else finalizable_hash [i] = entry->next; hash_table->num_registered--; entry->object = copy; /* insert it into the major hash */ rehash_fin_table_if_necessary (&major_finalizable_hash); major_hash = mono_object_hash ((MonoObject*) copy) % major_finalizable_hash.size; entry->next = major_finalizable_hash.table [major_hash]; major_finalizable_hash.table [major_hash] = entry; major_finalizable_hash.num_registered++; DEBUG (5, fprintf (gc_debug_file, "Promoting finalization of object %p (%s) (was at %p) to major table\n", copy, safe_name (copy), from)); entry = next; continue; } else { /* update pointer */ DEBUG (5, fprintf (gc_debug_file, "Updating object for finalization: %p (%s) (was at %p)\n", entry->object, safe_name (entry->object), from)); entry->object = copy; } } } prev = entry; entry = entry->next; } } }
/* LOCKING: requires that the GC lock is held */ static int finalizers_for_domain (MonoDomain *domain, MonoObject **out_array, int out_size, FinalizeEntryHashTable *hash_table) { FinalizeEntry **finalizable_hash = hash_table->table; mword finalizable_hash_size = hash_table->size; FinalizeEntry *entry, *prev; int i, count; if (no_finalize || !out_size || !out_array) return 0; count = 0; for (i = 0; i < finalizable_hash_size; ++i) { prev = NULL; for (entry = finalizable_hash [i]; entry;) { if (mono_object_domain (entry->object) == domain) { FinalizeEntry *next; /* remove and put in out_array */ if (prev) prev->next = entry->next; else finalizable_hash [i] = entry->next; next = entry->next; hash_table->num_registered--; out_array [count ++] = entry->object; DEBUG (5, fprintf (gc_debug_file, "Collecting object for finalization: %p (%s) (%d/%d)\n", entry->object, safe_name (entry->object), num_ready_finalizers, hash_table->num_registered)); entry = next; if (count == out_size) return count; continue; } prev = entry; entry = entry->next; } } return count; }
static void pin_pinned_object_callback (void *addr, size_t slot_size, SgenGrayQueue *queue) { binary_protocol_pin (addr, (gpointer)SGEN_LOAD_VTABLE (addr), mono_sgen_safe_object_get_size ((MonoObject*)addr)); if (!SGEN_OBJECT_IS_PINNED (addr)) mono_sgen_pin_stats_register_object ((char*) addr, mono_sgen_safe_object_get_size ((MonoObject*) addr)); SGEN_PIN_OBJECT (addr); GRAY_OBJECT_ENQUEUE (queue, addr); DEBUG (6, fprintf (gc_debug_file, "Marked pinned object %p (%s) from roots\n", addr, safe_name (addr))); }
static void major_copy_or_mark_object (void **obj_slot, SgenGrayQueue *queue) { char *forwarded; char *obj = *obj_slot; mword objsize; DEBUG (9, g_assert (current_collection_generation == GENERATION_OLD)); HEAVY_STAT (++stat_copy_object_called_major); DEBUG (9, fprintf (gc_debug_file, "Precise copy of %p from %p", obj, obj_slot)); /* * obj must belong to one of: * * 1. the nursery * 2. the LOS * 3. a pinned chunk * 4. a non-to-space section of the major heap * 5. a to-space section of the major heap * * In addition, objects in 1, 2 and 4 might also be pinned. * Objects in 1 and 4 might be forwarded. * * Before we can copy the object we must make sure that we are * allowed to, i.e. that the object not pinned, not already * forwarded and doesn't belong to the LOS, a pinned chunk, or * a to-space section. * * We are usually called for to-space objects (5) when we have * two remset entries for the same reference. The first entry * copies the object and updates the reference and the second * calls us with the updated reference that points into * to-space. There might also be other circumstances where we * get to-space objects. */ if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj))) { DEBUG (9, g_assert (((MonoVTable*)SGEN_LOAD_VTABLE(obj))->gc_descr)); DEBUG (9, fprintf (gc_debug_file, " (already forwarded to %p)\n", forwarded)); HEAVY_STAT (++stat_major_copy_object_failed_forwarded); *obj_slot = forwarded; return; } if (SGEN_OBJECT_IS_PINNED (obj)) { DEBUG (9, g_assert (((MonoVTable*)SGEN_LOAD_VTABLE(obj))->gc_descr)); DEBUG (9, fprintf (gc_debug_file, " (pinned, no change)\n")); HEAVY_STAT (++stat_major_copy_object_failed_pinned); return; } if (ptr_in_nursery (obj)) goto copy; /* * At this point we know obj is not pinned, not forwarded and * belongs to 2, 3, 4, or 5. * * LOS object (2) are simple, at least until we always follow * the rule: if objsize > SGEN_MAX_SMALL_OBJ_SIZE, pin the * object and return it. At the end of major collections, we * walk the los list and if the object is pinned, it is * marked, otherwise it can be freed. * * Pinned chunks (3) and major heap sections (4, 5) both * reside in blocks, which are always aligned, so once we've * eliminated LOS objects, we can just access the block and * see whether it's a pinned chunk or a major heap section. */ objsize = SGEN_ALIGN_UP (mono_sgen_safe_object_get_size ((MonoObject*)obj)); if (G_UNLIKELY (objsize > SGEN_MAX_SMALL_OBJ_SIZE || obj_is_from_pinned_alloc (obj))) { if (SGEN_OBJECT_IS_PINNED (obj)) return; DEBUG (9, fprintf (gc_debug_file, " (marked LOS/Pinned %p (%s), size: %zd)\n", obj, safe_name (obj), objsize)); binary_protocol_pin (obj, (gpointer)SGEN_LOAD_VTABLE (obj), mono_sgen_safe_object_get_size ((MonoObject*)obj)); SGEN_PIN_OBJECT (obj); GRAY_OBJECT_ENQUEUE (queue, obj); HEAVY_STAT (++stat_major_copy_object_failed_large_pinned); return; } /* * Now we know the object is in a major heap section. All we * need to do is check whether it's already in to-space (5) or * not (4). */ if (MAJOR_OBJ_IS_IN_TO_SPACE (obj)) { DEBUG (9, g_assert (objsize <= SGEN_MAX_SMALL_OBJ_SIZE)); DEBUG (9, fprintf (gc_debug_file, " (already copied)\n")); HEAVY_STAT (++stat_major_copy_object_failed_to_space); return; } copy: HEAVY_STAT (++stat_objects_copied_major); *obj_slot = copy_object_no_checks (obj, queue); }