static void thread_func(co_thread_t * self) { args_t & args = * (args_t*) co_get_user(self); for (uint32_t to=999999;to;--to) { if (--args.val_) { uint32_t next = rand64() % num_threads; co_yield(self, args.thread_[next]); } else { co_yield(self, args.host_); } } }
static int timing_yield(lua_State *L) { #ifdef DEBUG_LOG lua_State *from = lua_tothread(L, -1); #endif lua_rawget(L, lua_upvalueindex(2)); // check total time if (lua_isnil(L, -1)) { lua_pop(L,1); } else { double ti = lua_tonumber(L, -1); lua_pop(L,1); lua_pushthread(L); lua_rawget(L, lua_upvalueindex(1)); double starttime = lua_tonumber(L, -1); lua_pop(L,1); double diff = diff_time(starttime); ti += diff; #ifdef DEBUG_LOG fprintf(stderr, "PROFILE [%p] yield (%lf/%lf)\n", from, diff, ti); #endif lua_pushthread(L); lua_pushnumber(L, ti); lua_rawset(L, lua_upvalueindex(2)); } lua_CFunction co_yield = lua_tocfunction(L, lua_upvalueindex(3)); return co_yield(L); }
static void thread_a(co_thread_t * self) { assert(co_get_user(self)); args_t & args = * (args_t*) co_get_user(self); co_yield(self, args.b_); assert(!"Should not get here"); }
static int timing_yield(lua_State *L) { // printf("%s(%d): %d\n", __FUNCTION__, __LINE__, lua_gettop(L)); #ifdef DEBUG_LOG lua_State *from = lua_tothread(L, -1); #endif lua_rawget(L, lua_upvalueindex(2)); // check total time, 当前函数第二个upvalue指向的index,该index指向一个table,栈顶为key,key为一个协程,从lyield传入,取table[key]压栈 if (lua_isnil(L, -1)) { lua_pop(L,1); // printf("%s(%d): %d\n", __FUNCTION__, __LINE__, lua_gettop(L)); } else { double ti = lua_tonumber(L, -1); // total time lua_pop(L,1); lua_pushthread(L); // 协程压入 lua_rawget(L, lua_upvalueindex(1)); // 当前函数的第一个upvalue指向的index,该index指向的table,以上面的协程为索引,取得starttime double starttime = lua_tonumber(L, -1); // start time lua_pop(L,1); double diff = diff_time(starttime); // now - start time ti += diff; // 更新时间开销 #ifdef DEBUG_LOG fprintf(stderr, "PROFILE [%p] yield (%lf/%lf)\n", from, diff, ti); // printf("%s(%d): %d\n", __FUNCTION__, __LINE__, lua_gettop(L)); #endif lua_pushthread(L); // 协程入栈作为key lua_pushnumber(L, ti); // 更新后的ti入栈作为value lua_rawset(L, lua_upvalueindex(2)); // 更新当前函数第二个upvalue指向的index指向的table,t[key]=value } lua_CFunction co_yield = lua_tocfunction(L, lua_upvalueindex(3)); // lua_CFuntion是一个c函数指针类型,面向lua调用的一个接口,取出当前函数的第三个upvalue指向的index指向的函数指针 return co_yield(L); // 执行这个函数 }
static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs, int64_t offset, size_t size, QEMUIOVector *qiov) { ssize_t r; size_t got; char *buf, *end_of_vec; struct iovec *i; DPRINTF("offset=%" PRIi64 " size=%zu", offset, size); ssh_seek(s, offset, SSH_SEEK_READ); /* This keeps track of the current iovec element ('i'), where we * will write to next ('buf'), and the end of the current iovec * ('end_of_vec'). */ i = &qiov->iov[0]; buf = i->iov_base; end_of_vec = i->iov_base + i->iov_len; /* libssh2 has a hard-coded limit of 2000 bytes per request, * although it will also do readahead behind our backs. Therefore * we may have to do repeated reads here until we have read 'size' * bytes. */ for (got = 0; got < size; ) { again: DPRINTF("sftp_read buf=%p size=%zu", buf, end_of_vec - buf); r = libssh2_sftp_read(s->sftp_handle, buf, end_of_vec - buf); DPRINTF("sftp_read returned %zd", r); if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) { co_yield(s, bs); goto again; } if (r < 0) { sftp_error_report(s, "read failed"); s->offset = -1; return -EIO; } if (r == 0) { /* EOF: Short read so pad the buffer with zeroes and return it. */ qemu_iovec_memset(qiov, got, 0, size - got); return 0; } got += r; buf += r; s->offset += r; if (buf >= end_of_vec && got < size) { i++; buf = i->iov_base; end_of_vec = i->iov_base + i->iov_len; } } return 0; }
int32_t test_unchained() { args_t args; args.host_ = co_init(nullptr); args.val_ = 100000; for (uint32_t i = 0; i < num_threads; ++i) { args.thread_[i] = co_create (args.host_, thread_func, 1024, nullptr); assert(args.thread_[i]); co_set_user(args.thread_[i], &args); } co_yield(args.host_, args.thread_[0]); assert(args.val_ == 0); return 0; }
int32_t test_yieldmain() { args_t args; args.host_ = co_init(nullptr); args.a_ = co_create (args.host_, thread_a, 1024, nullptr, &args); args.b_ = co_create (args.host_, thread_b, 1024, nullptr, &args); co_yield(args.host_, args.a_); co_delete(args.a_); co_delete(args.b_); co_delete(args.host_); return 0; }
static coroutine_fn int ssh_flush(BDRVSSHState *s, BlockDriverState *bs) { int r; DPRINTF("fsync"); again: r = libssh2_sftp_fsync(s->sftp_handle); if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) { co_yield(s, bs); goto again; } if (r == LIBSSH2_ERROR_SFTP_PROTOCOL && libssh2_sftp_last_error(s->sftp) == LIBSSH2_FX_OP_UNSUPPORTED) { unsafe_flush_warning(s, "OpenSSH >= 6.3"); return 0; } if (r < 0) { sftp_error_report(s, "fsync failed"); return -EIO; } return 0; }
static int ssh_write(BDRVSSHState *s, BlockDriverState *bs, int64_t offset, size_t size, QEMUIOVector *qiov) { ssize_t r; size_t written; char *buf, *end_of_vec; struct iovec *i; DPRINTF("offset=%" PRIi64 " size=%zu", offset, size); ssh_seek(s, offset, SSH_SEEK_WRITE); /* This keeps track of the current iovec element ('i'), where we * will read from next ('buf'), and the end of the current iovec * ('end_of_vec'). */ i = &qiov->iov[0]; buf = i->iov_base; end_of_vec = i->iov_base + i->iov_len; for (written = 0; written < size; ) { again: DPRINTF("sftp_write buf=%p size=%zu", buf, end_of_vec - buf); r = libssh2_sftp_write(s->sftp_handle, buf, end_of_vec - buf); DPRINTF("sftp_write returned %zd", r); if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) { co_yield(s, bs); goto again; } if (r < 0) { sftp_error_report(s, "write failed"); s->offset = -1; return -EIO; } /* The libssh2 API is very unclear about this. A comment in * the code says "nothing was acked, and no EAGAIN was * received!" which apparently means that no data got sent * out, and the underlying channel didn't return any EAGAIN * indication. I think this is a bug in either libssh2 or * OpenSSH (server-side). In any case, forcing a seek (to * discard libssh2 internal buffers), and then trying again * works for me. */ if (r == 0) { ssh_seek(s, offset + written, SSH_SEEK_WRITE|SSH_SEEK_FORCE); co_yield(s, bs); goto again; } written += r; buf += r; s->offset += r; if (buf >= end_of_vec && written < size) { i++; buf = i->iov_base; end_of_vec = i->iov_base + i->iov_len; } if (offset + written > s->attrs.filesize) s->attrs.filesize = offset + written; } return 0; }
void CoYield(void * pCoID) { co_yield((stCoRoutine_t *)pCoID); }