美文网首页
MudOS简单源码剖析

MudOS简单源码剖析

作者: 1angxi | 来源:发表于2015-07-29 18:40 被阅读1645次

    暂时没任务,了解一下MudOS的源码。推荐使用vim来看,搭配上ctags插件跳转函数定义。

    下面先来讲一讲数据类型:array、mapping、string。

    array

    array类似于其他语言中线性表的概念,比如说:c++语言的vector、python的list。array.h中定义了结构体array_t,array_t就是主要的存储数据的类型:

    typedef struct array_s { 
        unsigned short ref;  
        int extra_ref;
        unsigned short size;
        svalue_t item[1];
    }
    

    上面的svalue_t item[1];就是存储具体数据的地方。明显是一个数组。svaluet_t是一个结构体类型,定义在lpc.h中:

     37 typedef struct svalue_s {
     38     short type;
     39     short subtype;
     40     union u u;
     41 } svalue_t;    
    
     11 union u {
     12     char *string;
     13     int number;
     14     float real;
     15 
     16     refed_t *refed; /* any of the block below */
     21     struct object_s *ob;
     22     struct array_s *arr;
     23     struct mapping_s *map;
     24     struct funptr_s *fp;
     25 
     26     struct svalue_s *lvalue;
     27     struct ref_s *ref;
     28     unsigned char *lvalue_byte;
     29     void (*error_handler) PROT((void));
     30 };
    

    通过上面基本上了解到array是如何定义的了。

    比较有意思的是array提供的一个排序函数:f_sort_array。

    内部使用的是快速排序,快速排序定义在qsort.c中。

    可以看到关于快排的注释:

    /* qsort adapted from page 87 of K&R 2nd edition */ 
    

    Mudos作者引用了K&R写的c程序设计第2版的87页。

    附上array支持的函数:

    allocate() - 配置内存给一个有 size 个元素的数组
    arrayp() - 看一个给定的变量是否为数组 (array).
    filter_array() - 返回一个过滤旧数组内容的新数组.
    map_array() - 经由一个函数修改一个数组的元素 (element)
    member_array() -  在一个数组 (array)  或字符串 (string) 中找寻指定的项目 (item)
    pointerp() -  判断指定的变量是否为一个数组 (array).
    sort_array() - 将一个数组的内容排序.
    unique_array() - 将一个物件数组分组.
    

    mapping

    在mapping.h中定义了mapping在内存中实际的类型:

     32 typedef struct mapping_s {                                                                                                                                                                       
     33     unsigned short ref;     /* how many times this map has been* referenced */                                                                                                                                                                                                                                                                                                                                                      
     38     mapping_node_t **table; /* the hash table */                                                                                                                                                 
     39     unsigned short table_size;  /* # of buckets in hash table == power of 2 */                                                                                                                   
     40     unsigned short unfilled;    /* # of buckets among 80% of total buckets that do not have entries */                                                                                           
     41     unsigned int count;     /* total # of nodes actually in mapping  */                                                                                                                                                                                                                                                                                                                   
     45 } mapping_t; 
    
     11 typedef struct mapping_node_s {
     12     struct mapping_node_s *next;    
     13     svalue_t values[2];    
     14 } mapping_node_t; 
    

    从注释很容易可以看出来,mapping底层是用hash_table来存储数据的。

    很想吐槽这注释....

    mapping_node_t **table;可以知道,使用的是链地址法的方式实现的hashtable。

    下面看一个返回所有value值的函数实现(mapping.c):

    1256 /* mapping_values */                                                                                                                                                  
    1257                                                                                                                                                                       
    1258 array_t *                                                                                                                                                             
    1259 mapping_values P1(mapping_t *,m)                                                                                                                                      
    1260 {                                                                                                                                                                     
    1261     array_t *v;                                                                                                                                                       
    1262     int j = m->table_size;                                                                                                                                            
    1263     mapping_node_t *elt, **a = m->table;                                                                                                                              
    1264     svalue_t *sv;                                                                                                                                                     
    1265                                                                                                                                                                       
    1266     debug(mapping,("mapping_values: size = %d\n",MAP_COUNT(m)));                                                                                                      
    1267                                                                                                                                                                       
    1268     v = allocate_empty_array(MAP_COUNT(m));                                                                                                                           
    1269     sv = v->item;                                                                                                                                                     
    1270     do {
    1271         for (elt = a[j]; elt; elt = elt->next)
    1272         assign_svalue_no_free(sv++, elt->values + 1);
    1273     } while (j--);
    1274     return v;
    1275 }
    

    很容易就能看懂。其实就是对于mapping的一次遍历。

    附上mappings支持的函数:

    allocate_mapping() - 预先配置 (pre-allocate) 一块内存给一个映射 (mapping).
    each() - 分次返回一个映射变量 (mapping) 的各个 (key, value) 的内容.
    filter_mapping() - 以一个函数为准, 移除一个映射变量中的某些元素.
    keys() - 返回在一个映射变量 (mapping) 中所有 (关键字, 内容值) (即 (key, value) ) 数据关键字的数组 (array).
    values() - 从一个映射变量的 (关键字, 内容值) ( (keys, values) )  中, 以数组返回内容值.
    map_delete() -  以关键字从一个映射变量中删除一对 (关键字, 内容值) ((key, value)).
    map_mapping() - 经由一个函数修改一个映射变量中的元素
    mapp() - 判断一个指定的变量是否为映射变量 (mapping).
    match_path() - 在一个映射变量 (mapping) 中找寻路径名称 (path)
    unique_mapping() - 以一个函数为准, 从一个数组另创一个映射 (mapping).
    

    string

    string其实就是一个对于字符数组的封装。

    string在mudos内的定义位于stralloc.h和stralloc.c中。来看看stralloc.h声明的函数有:

    125 void init_strings PROT((void));  //初始化字符串                                                                                                                        
    126 char *findstring PROT((char *));  //查找字符串                                                                                                                       
    127 char *make_shared_string PROT((char *));  //共享字符串                                                                                                                 
    128 char *ref_string PROT((char *));  //引用字符串                                                                                                                         
    129 void free_string PROT((char *));  //释放字符串                                                                                                                         
    130 void deallocate_string PROT((char *));  //解除string的内存分配                                                                                                         
    131 int add_string_status PROT((outbuffer_t *, int));  //增加字符串的状态                                                                                                      
    

    来看一下init_strings函数:

     85 void init_strings()                                                                                                                                                    
     86 {                                                                                                                                                                       87     int x, y;                                                                                                                                                          
     88                                                                                                                                                                        
     89     /* ensure that htable size is a power of 2 */                                                                                                                      
     90     y = HTABLE_SIZE;                                                                                                                                                   
     91     for (htable_size = 1; htable_size < y; htable_size *= 2)                                                                                                           
     92     ;                                                                                                                                                                  
     93     htable_size_minus_one = htable_size - 1;                                                                                                                           
     94     base_table = CALLOCATE(htable_size, block_t *,                                                                                                                     
     95                TAG_STR_TBL, "init_strings");                                                                                                                                                                                                                                                                                      
     99                                                                                                                                                                        
    100     for (x = 0; x < htable_size; x++) {                                                                                                                                
    101     base_table[x] = 0;                                                                                                                                                 
    102     }                                                                                                                                                                  
    103 }  
    

    mudos的底层是通过hashtable来管理string的。init_strings函数就是初始化这个hashtable。

    再来看看findstring :

    141 char *
    142      findstring P1(char *, s)
    143 {
    144     block_t *b;
    145 
    146     if ((b = findblock(s))) {
    147     return STRING(b);
    148     } else {
    149     return (NULL);
    150     }
    151 }
    
     67 #define findblock(s) sfindblock(s, StrHash(s))
    
    112 INLINE_STATIC block_t *
    113         sfindblok P2(char *, s, int, h)
    114 {
    115     block_t *curr, *prev;
    116 
    117     curr = base_table[h];
    118     prev = NULL;
    119 #ifdef STRING_STATS
    120     num_str_searches++;
    121 #endif
    122 
    123     while (curr) {
    124 #ifdef STRING_STATS
    125     search_len++;
    126 #endif
    127     if (*(STRING(curr)) == *s && !strcmp(STRING(curr), s)) {    /* found it */
    128         if (prev) {     /* not at head of list */
    129         NEXT(prev) = NEXT(curr);
    130         NEXT(curr) = base_table[h];
    131         base_table[h] = curr;
    132         }
    133         return (curr);  /* pointer to string */
    134     }
    135     prev = curr;
    136     curr = NEXT(curr);
    137     }
    138     return ((block_t *) 0); /* not found */
    139 }
    

    find_string就是在hashtable中去查找给定字符串。查找步骤如下:

    1、通过hash(s)确定s所在的桶。
    2、顺序查找单链表。
    3、如果找到了,并且不是单链表头结点,就提前到头结点。
    4、返回结果。

    mudos的string也是用了慢拷贝来做的。慢拷贝是指如果新定义的字符串已经存在的话,就增加对这个字符串的引用,而不是新开一块内存去存储。这样的做法就导致了,string不能改,改起来会特别麻烦。

    每个string都带了一个引用计数器。一般这种引用计数的话,在多线程情况下会出现竞争,因为i++不是原子的,转换成汇编语句会变成:

    mov eax,【xxxxxxxx】
    inc   eax
    ```
    
    因为两条语句中间可能会出现中断,move指令执行之后,此时如果转入到另外一条线程下面,刚好也执行了move指令,那么两个线程各自的eax都加了一,但是实际上应该加二才对。
    
    一种比较简单处理是在原子语句之间先关闭中断,然后进行原子操作后再
    打开中断就OK了。
    
    efuns提供的关于string的函数有:
    
    ```
    stringp() - 判断一个变量是否为字符串类型 (string).
    break_string() - 以固定的间隔打断一个字符串 (string).返回一个字符串
    capitalize() - 把一个字符串的第一个英文字符 (character) 转成大写.
    clear_bit() - 清除一个字符串中的某一个 bit .
    crypt() - 对一个字符串进行编码.
    explode() - 打断一个字符串.返回字符串数组
    implode() - 连结多个字符串.
    lower_case() - 转换一个指定字符串的内容为小写
    reg_assoc() - 一个正规样式 (regular pattern) 子字符串撷取器(extractor)
    regexp() - 正规描述式(regular expression)处理程序
    replace_string() - 替换一个字符串中符合条件的字.
    set_bit() - 设定一个位元字符串 (bitstring) 中的一个位元 (bit).
    printf, sprintf - 转换成指定格式的输出结果.
    sscanf() - 从一个字符串中读进与指定格式相符的数据.
    strcmp() - 判断两个字符串间的语句关系 (lexical relationship).
    strlen() - 返回一个字符串的长度
    strsrch() - 在一个字符串中寻找特定的字符串.
    test_bit() - 检查一个位元字符串 (bitstring) 中某一个位元 (bit) 的值.
    ```
    
    
    
    
    
    

    相关文章

      网友评论

          本文标题:MudOS简单源码剖析

          本文链接:https://www.haomeiwen.com/subject/bugmqttx.html