资源注册

6.2.1.2 资源注册

初始化完成各模块就可以各自进行资源注册了,注册后TSRM会给注册的资源分配唯一id,之后对此资源的操作只能依据此id,接下来我们以EG为例具体看下其注册过程。

#ifdef ZTS
ZEND_API int executor_globals_id;
#endif

int zend_startup(zend_utility_functions *utility_functions, char **extensions)
{
    ...
#ifdef ZTS
    ts_allocate_id(&executor_globals_id, sizeof(zend_executor_globals), (ts_allocate_ctor) executor_globals_ctor, (ts_allocate_dtor) executor_globals_dtor);

    executor_globals = ts_resource(executor_globals_id);
    ...
#endif
}

资源注册调用ts_allocate_id()完成,此函数有4个参数有,第一个就是定义的资源id指针,注册之后会把分配的id写到这里,第二个是资源类型的大小,EG资源的结构是zend_executor_globals,所以这个值就是sizeof(zend_executor_globals),后面两个分别是资源的初始化函数以及销毁函数,因为TSRM并不关心资源的具体类型,分配资源时它只按照size大小分配内存,然后回调各资源自己定义的ctor进行初始化。

TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
{
    //加锁,保证各线程串行调用此函数
    tsrm_mutex_lock(tsmm_mutex);

    //分配id,即id_count当前值,然后把id_count加1
    *rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++);

    //检查resource_types_table数组当前大小是否已满
    if (resource_types_table_size < id_count) {
        //需要对resource_types_table扩容
        resource_types_table = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count);
        ...
        //把数组大小修改新的大小
        resource_types_table_size = id_count;
    }

    //将新注册的资源插入resource_types_table数组,下标就是分配的资源id
    resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].size = size;
    resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor;
    resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor;
    resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0;
    ...
}

到这里并没有结束,所有的资源并不是统一时机注册的,所以注册一个新资源时可能有线程已经分配先前注册的资源了,因此需要对各线程的storage数组进行扩容,否则storage将没有空间容纳新的资源。扩容的过程比较简单:遍历各线程的tsrm_tls_entry,检查storage当时是否有空闲空间,有的话跳过,没有的话则扩展。

for (i=0; icount < id_count) {
            int j;

            //将storage扩容
            p->storage = (void *) realloc(p->storage, sizeof(void *)*id_count);
            //分配并初始化新注册的资源,实际这里只会执行一次,不清楚为什么用循环
            //另外这里不分配内存也可以,可以放到使用时再去分配
            for (j=p->count; jstorage[j] = (void *) malloc(resource_types_table[j].size);
                if (resource_types_table[j].ctor) {
                    //回调初始化函数进行初始化
                    resource_types_table[j].ctor(p->storage[j]);
                }
            }
            p->count = id_count;
        }
        p = p->next;
    }
}

最后将锁释放,完成注册。

联系我们

邮箱 626512443@qq.com
电话 18611320371(微信)
QQ群 235681453

Copyright © 2015-2024

备案号:京ICP备15003423号-3