初始化完成各模块就可以各自进行资源注册了,注册后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