1.ZTS zend thread safety,php线程安全,适用于Apache2+worker MPM
2.ts_allocate_id:allocates a new thread-safe-resource id;函数 TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor);rsrc_id是指针类型,会在ts_allocate_id函数内部给出值;ctor/dtor资源初始化和销毁的函数指针
tsrm_tls_entry:每个线程拥有一个tsrm_tls_entry结构,当前线程的所有资源保存在storage数组中,storage中的下标就是各资源的id,由ts_allocate_id分配;
struct _tsrm_tls_entry {
void **storage;
int count;
THREAD_T thread_id;
tsrm_tls_entry *next;
};
tsrm_tls_table:所有线程的tsrm_tls_entry结构通过一个数组保存:tsrm_tls_table,这是个全局变量,每个线程的tsrm_tls_entry结构在这个数组中的位置是根据线程id与预设置的线程数(tsrm_tls_table_size)取模得到的,也就是说有可能多个线程保存在tsrm_tls_table同一位置,所以tsrm_tls_entry是个链表,查找资源时首先根据:线程id % tsrm_tls_table_size得到一个tsrm_tls_entry,然后开始遍历链表比较thread_id确定是否是当前线程的。
tsrm_tls_table结构如图:
3.ts_allocate_id源码赏析
/* allocates a new thread-safe-resource id */
TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
{/*{{{*/
int i;
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new resource id, %d bytes", size));
tsrm_mutex_lock(tsmm_mutex);//锁
/* obtain a resource id */
*rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++);//分配资源id
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtained resource id %d", *rsrc_id));
/* store the new resource type in the resource sizes table */
if (resource_types_table_size < id_count) {//线程中的所有不共享的全局资源表
tsrm_resource_type *_tmp;
_tmp = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count);
if (!_tmp) {
tsrm_mutex_unlock(tsmm_mutex);
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate storage for resource"));
*rsrc_id = 0;
return 0;
}
resource_types_table = _tmp;
resource_types_table_size = id_count;
}
/*
*为当前资源构建tsrm_resource_type结构
**/
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;
/* 遍历线程资源表tsrm_tls_table_size,为每一个线程的资源中添加新加入的这个资源,并初始化*/
for (i=0; i<tsrm_tls_table_size; i++) {
tsrm_tls_entry *p = tsrm_tls_table[i];//取出线程资源链表的表头,thread_id%thread_size == i
while (p) {//对链表中的每一项做处理
if (p->count < id_count) {
int j;
p->storage = (void *) realloc(p->storage, sizeof(void *)*id_count);
for (j=p->count; j<id_count; j++) {
p->storage[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;
}
}
tsrm_mutex_unlock(tsmm_mutex);
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully allocated new resource id %d", *rsrc_id));
return *rsrc_id;
}/*}}}*/