// 收回handle void skynet_handle_retire(uint32_t handle) { struct handle_storage *s = H; rwlock_wlock(&s->lock); uint32_t hash = handle & (s->slot_size-1); // 等价于 handle % s->slot_size struct skynet_context * ctx = s->slot[hash]; if (ctx != NULL && skynet_context_handle(ctx) == handle) { skynet_context_release(ctx); // free skynet_ctx s->slot[hash] = NULL; // 置空,哈希表腾出空间 int i; int j=0, n=s->name_count; for (i=0; i<n; ++i) { if (s->name[i].handle == handle) { // 在 name 表中 找到 handle 对应的 name free掉 free(s->name[i].name); continue; } else if (i!=j) { // 说明free了一个name s->name[j] = s->name[i]; // 因此需要将后续元素移到前面 } ++j; } s->name_count = j; } rwlock_wunlock(&s->lock); }
void skynet_handle_retire(uint32_t handle) { struct handle_storage *s = H; rwlock_wlock(&s->lock); uint32_t hash = handle & (s->slot_size-1); struct skynet_context * ctx = s->slot[hash]; if (ctx != NULL && skynet_context_handle(ctx) == handle) { skynet_context_release(ctx); s->slot[hash] = NULL; int i; int j=0, n=s->name_count; for (i=0; i<n; ++i) { if (s->name[i].handle == handle) { free(s->name[i].name); continue; } else if (i!=j) { s->name[j] = s->name[i]; } ++j; } s->name_count = j; } rwlock_wunlock(&s->lock); }
id_t index_regist(struct index *idx, void *ud) { if (!ud) return 0; rwlock_wlock(&idx->lock); if (idx->cnt >= idx->cap * 3 / 4) { if (!_index_expand(idx)) { rwlock_wunlock(&idx->lock); return 0; } } for (;;) { struct slot *slot; id_t id = ++idx->last; if (id == 0) { id = ++idx->last; } slot = &idx->slot[HASH(id)]; if (slot->id) continue; slot->id = id; slot->ref = 1; slot->ud = ud; ++idx->cnt; rwlock_wunlock(&idx->lock); return id; } }
handleid handlemap_new(struct handlemap *m, void *ud) { int i; if (ud == NULL) return 0; rwlock_wlock(&m->lock); if (m->n >= m->cap * 3 / 4) { if (expand_map(m) == NULL) { // memory overflow rwlock_wunlock(&m->lock); return 0; } } for (i=0;;i++) { struct handleslot *slot; handleid id = ++m->lastid; if (id == 0) { // 0 is reserved for invalid id id = ++m->lastid; } slot = &m->slot[id & (m->cap - 1)]; if (slot->id) continue; slot->id = id; slot->ref = 1; slot->ud = ud; ++m->n; rwlock_wunlock(&m->lock); return id; } }
void * index_release(struct index *idx, id_t id) { struct slot *slot; void *ud = 0; if (id == 0) return 0; rwlock_rlock(&idx->lock); slot = &idx->slot[HASH(id)]; if (slot->id != id) { rwlock_runlock(&idx->lock); return 0; } if (atom_dec(&slot->ref) <= 0) ud = slot->ud; rwlock_runlock(&idx->lock); if (ud > 0) { rwlock_wlock(&idx->lock); slot = &idx->slot[HASH(id)]; if (slot->id != id) { rwlock_wunlock(&idx->lock); return 0; } if (slot->ref > 0) { rwlock_wunlock(&idx->lock); return 0; } ud = slot->ud; slot->id = 0; --idx->cnt; rwlock_wunlock(&idx->lock); return ud; } return 0; }
uint32_t skynet_handle_register(struct skynet_context *ctx) { struct handle_storage *s = H; rwlock_wlock(&s->lock); for (;;) { int i; for (i=0;i<s->slot_size;i++) { uint32_t handle = (i+s->handle_index) & HANDLE_MASK; int hash = handle & (s->slot_size-1); if (s->slot[hash] == NULL) { s->slot[hash] = ctx; s->handle_index = handle + 1; rwlock_wunlock(&s->lock); handle |= s->harbor; return handle; } } assert((s->slot_size*2 - 1) <= HANDLE_MASK); struct skynet_context ** new_slot = skynet_malloc(s->slot_size * 2 * sizeof(struct skynet_context *)); memset(new_slot, 0, s->slot_size * 2 * sizeof(struct skynet_context *)); for (i=0;i<s->slot_size;i++) { int hash = skynet_context_handle(s->slot[i]) & (s->slot_size * 2 - 1); assert(new_slot[hash] == NULL); new_slot[hash] = s->slot[i]; } skynet_free(s->slot); s->slot = new_slot; s->slot_size *= 2; } }
//收回handle int server_handle_retire(uint32_t handle) { int ret = 0; struct handle_storage *s = H; rwlock_wlock(&s->lock); uint32_t hash = handle & (s->slot_size-1); struct server_context * ctx = s->slot[hash]; if (ctx != NULL && server_context_handle(ctx) == handle) { s->slot[hash] = NULL;//置空,哈希表腾出空间 ret = 1; int i; int j=0, n=s->name_count; for (i=0; i<n; ++i) { if (s->name[i].handle == handle) {//在 name 表中 找到 handle 对应的 name free掉 server_free(s->name[i].name); continue; } else if (i!=j) {//说明free了一个name s->name[j] = s->name[i];//因此需要将后续元素移到前面 } ++j; } s->name_count = j; } rwlock_wunlock(&s->lock); if (ctx) { server_context_release(ctx);//free server_ctx } return ret; }
// name与handle绑定 // 给服务注册一个名称的时候会用到该函数 const char * skynet_handle_namehandle(uint32_t handle, const char *name) { rwlock_wlock(&H->lock); const char * ret = _insert_name(H, name, handle); rwlock_wunlock(&H->lock); return ret; }
static void stm_update(struct stm_object *obj, void *msg, int32_t sz) { struct stm_copy *copy = stm_newcopy(msg, sz); rwlock_wlock(&obj->lock); struct stm_copy *oldcopy = obj->copy; obj->copy = copy; rwlock_wunlock(&obj->lock); stm_releasecopy(oldcopy); }
int skynet_handle_retire(uint32_t handle) { int ret = 0; struct handle_storage *s = H; // 其他线程不能同时写 rwlock_wlock(&s->lock); // 获得索引 uint32_t hash = handle & (s->slot_size - 1); struct skynet_context * ctx = s->slot[hash]; if (ctx != NULL // 1. 判断是否在同一个节点 // 2. 确认 handle 是没有超出 slot_size 的, 因为可能 slot_size = 8, handle = 15, skynet_context_handle(ctx) = 7 // 3. 其他线程没有修改 ctx && skynet_context_handle(ctx) == handle) { s->slot[hash] = NULL; ret = 1; // 将关联注册的名字资源也一同释放掉 int i; int j = 0, n = s->name_count; for (i = 0; i < n; ++i) { if (s->name[i].handle == handle) { // 判断是否有注册名字 skynet_free(s->name[i].name); // 释放内存 continue; // 一个 handle 允许注册多个名字, 继续判断 } else if (i != j) { // 向数组的头部移动 s->name[j] = s->name[i]; } ++j; } // 更新当前注册了名字的 context 数量 s->name_count = j; } else { ctx = NULL; } rwlock_wunlock(&s->lock); if (ctx) { // release ctx may call skynet_handle_* , so wunlock first. // 释放 ctx 可能会调用到 skynet_handle_* 方法, 所以先解 [写] 锁 skynet_context_release(ctx); } return ret; }
static void stm_release(struct stm_object *obj) { assert(obj->copy); rwlock_wlock(&obj->lock); // writer release the stm object, so release the last copy . stm_releasecopy(obj->copy); obj->copy = NULL; if (--obj->reference > 0) { // stm object grab by readers, reset the copy to NULL. rwlock_wunlock(&obj->lock); return; } // no one grab the stm object, no need to unlock wlock. skynet_free(obj); }
void skynet_mq_pushmt(struct skynet_mq *mq, struct skynet_message_package *pack) { struct skynet_mq expand; if (perpare_space(mq, &expand)) { rwlock_wlock(&mq->lock); void * ptr = mq->q; if (mq->head < expand.head) { // the head changes (some one pop in another thread) between perpare_space and rwlock_wlock mq->head += mq->cap; } mq->q = expand.q; mq->cap = expand.cap; mq->tail = expand.tail; rwlock_wunlock(&mq->lock); skynet_free(ptr); } push_message(mq, pack); }
// 注册ctx,将 ctx 存到 handle_storage 哈希表中,并得到一个handle uint32_t skynet_handle_register(struct skynet_context *ctx) { struct handle_storage *s = H; rwlock_wlock(&s->lock); for (;;) { int i; for (i=0; i<s->slot_size; i++) { uint32_t handle = (i+s->handle_index) & HANDLE_MASK; int hash = handle & (s->slot_size-1); // 等价于 handle % s->slot_size if (s->slot[hash] == NULL) { // 找到未使用的 slot 将这个 ctx 放入这个 slot 中 s->slot[hash] = ctx; s->handle_index = handle + 1; // 移动 handle_index 方便下次使用 rwlock_wunlock(&s->lock); handle |= s->harbor; // harbor 用于不同主机间的通信 handle高8位用于harbor 低24位用于本机的 所以这里需要 |= 下 skynet_context_init(ctx, handle); // 设置 ctx->handle = handle; 即这个 ctx 的 handle return handle; } } assert((s->slot_size*2 - 1) <= HANDLE_MASK); // 确保 扩大2倍空间后 总共handle即 slot的数量不超过 24位的限制 // 哈希表扩大2倍 struct skynet_context ** new_slot = malloc(s->slot_size * 2 * sizeof(struct skynet_context *)); memset(new_slot, 0, s->slot_size * 2 * sizeof(struct skynet_context *)); // 将原来的数据拷贝到新的空间 for (i=0;i<s->slot_size;i++) { int hash = skynet_context_handle(s->slot[i]) & (s->slot_size * 2 - 1); // 映射新的 hash 值 assert(new_slot[hash] == NULL); new_slot[hash] = s->slot[i]; } free(s->slot); // free old mem s->slot = new_slot; s->slot_size *= 2; } }
static void * try_delete(struct handlemap *m, handleid id) { struct handleslot * slot; void * ud; if (id == 0) return NULL; rwlock_wlock(&m->lock); slot = &m->slot[id & (m->cap - 1)]; if (slot->id != id) { rwlock_wunlock(&m->lock); return NULL; } if (slot->ref > 0) { rwlock_wunlock(&m->lock); return NULL; } ud = slot->ud; slot->id = 0; --m->n; rwlock_wunlock(&m->lock); return ud; }
int skynet_handle_retire(uint32_t handle) { int ret = 0; struct handle_storage *s = H; rwlock_wlock(&s->lock); uint32_t hash = handle & (s->slot_size-1); struct skynet_context * ctx = s->slot[hash]; if (ctx != NULL && skynet_context_handle(ctx) == handle) { s->slot[hash] = NULL; ret = 1; int i; int j=0, n=s->name_count; for (i=0; i<n; ++i) { if (s->name[i].handle == handle) { skynet_free(s->name[i].name); continue; } else if (i!=j) { s->name[j] = s->name[i]; } ++j; } s->name_count = j; } else { ctx = NULL; } rwlock_wunlock(&s->lock); if (ctx) { // release ctx may call skynet_handle_* , so wunlock first. skynet_context_release(ctx); } return ret; }
//注册ctx,将ctx存到handle_storage哈希表中,并得到一个handle uint32_t server_handle_register(struct server_context *ctx) { struct handle_storage *s = H; rwlock_wlock(&s->lock); for (;;) { int i; for (i=0;i<s->slot_size;i++) { uint32_t handle = (i+s->handle_index) & HANDLE_MASK;//高8位清0,保留低24位 int hash = handle & (s->slot_size-1);//保证handle不能大于slot_size,使得hash取值在[0, slot_size-1] if (s->slot[hash] == NULL) {//找到未使用的slot,将这个 ctx 放入这个 slot 中 s->slot[hash] = ctx; s->handle_index = handle + 1;//移动handle_index,方便下次使用 rwlock_wunlock(&s->lock); handle |= s->harbor;//高8位用于存放分布式id return handle; } } assert((s->slot_size*2 - 1) <= HANDLE_MASK);//确保 扩大2倍空间后 总共handle即 slot的数量不超过 24位的限制 //哈希表扩大2倍 struct server_context ** new_slot = server_malloc(s->slot_size * 2 * sizeof(struct server_context *)); memset(new_slot, 0, s->slot_size * 2 * sizeof(struct server_context *)); //将原来的数据拷贝到新的空间 for (i=0;i<s->slot_size;i++) { int hash = server_context_handle(s->slot[i]) & (s->slot_size * 2 - 1);//映射新的 hash 值 assert(new_slot[hash] == NULL); new_slot[hash] = s->slot[i]; } server_free(s->slot); s->slot = new_slot; s->slot_size *= 2; } }
uint32_t skynet_handle_register(struct skynet_context *ctx) { struct handle_storage *s = H; // 线程上锁, 保证线程安全 rwlock_wlock(&s->lock); for (;;) { // 注意, 这里是一个无限循环, 必须拿到一个可用的 handle int i; // 从头开始循环遍历 for (i=0;i<s->slot_size;i++) { uint32_t handle = (i+s->handle_index) & HANDLE_MASK; // 获得从右到左 3 个字节的数据, 最左的低 4 个字节(高 8 位)用来表示 harbor int hash = handle & (s->slot_size-1); // 获得实际的索引, hash 的值不超出 slot_size 的范围 // 当有可用的 slot 放入 ctx if (s->slot[hash] == NULL) { // 记录注册的 ctx s->slot[hash] = ctx; // handle_index 自增 s->handle_index = handle + 1; // 已经存储了 ctx 了, 可以解锁让其他线程使用了 rwlock_wunlock(&s->lock); // 新的 handle 需要使用高 8 位记录当前 handle 所属的 harbor handle |= s->harbor; return handle; } } // 当前进程不能超过 HANDLE_MASK 的数量 assert((s->slot_size*2 - 1) <= HANDLE_MASK); // 如果没有可用的空间, 扩展容量 // 申请新的内存空间, slot_size * 2 struct skynet_context ** new_slot = skynet_malloc(s->slot_size * 2 * sizeof(struct skynet_context *)); // 重置内存数据 memset(new_slot, 0, s->slot_size * 2 * sizeof(struct skynet_context *)); // 将原来的内容进行复制 for (i = 0; i < s->slot_size; i++) { // 获得在当前分配的空间中可用的索引, 注意这里是使用 (slot_size * 2 - 1) 在进行为操作. int hash = skynet_context_handle(s->slot[i]) & (s->slot_size * 2 - 1); assert(new_slot[hash] == NULL); // 这里为什么不是直接 new_slot[i] = s->slot[i] 呢, 而要绕个弯拿到 hash, 然后 new_slot[hash] = s->slot[i] // 解答, 很有意思的小细节: // 首先说 handle_index 从 1 开始计数, 而且都是不断的增加, 返回的时候使用的是 return handle |= s->harbor; 这就决定了返回值不会为 0 // 在上面的查询 slot, 并且分配 handle 的过程中, 索引是 hash, 返回值是 handle, handle 可以大于 slot_size. // 这里获得的 hash 可以是大于 slot_size 的, 那么现在可以举例: hash = 4, i = 0 // new_slot[4] = s->slot[0], 如果使用 new_slot[i] = s->slot[i] 这种方式, 那么对于结果上来说是没有什么影响的, 但是会出现这样一种情况: // 例如: 原来的 slot_size 是 7, 这时 handle_index 16, 全部的 slot 正在被使用. 那么现在需要扩展空间, slot_size 扩展到 16, 那么现在来看看 // new_slot 的分配情况是如何的: // 原来的 slot 是 [0, slot1, slot2, slot3, slot4, slot5, slot6, slot7] // 现在的 slot 是 [0, 0, 0, 0, 0, 0, 0, 0, 0, slot1, slot2, slot3, slot4, slot5, slot6, slot7] new_slot[hash] = s->slot[i]; } // 释放之前的数据 skynet_free(s->slot); // 记录新的数据 s->slot = new_slot; s->slot_size *= 2; } }