static gboolean connect_delayed(gpointer data) { SpiceChannel *channel = data; spice_channel *c = channel->priv; struct coroutine *co; SPICE_DEBUG("Open coroutine starting %p", channel); c->connect_delayed_id = 0; co = &c->coroutine; co->stack_size = 16 << 20; /* 16Mb */ co->entry = spice_channel_coroutine; co->release = NULL; coroutine_init(co); coroutine_yieldto(co, channel); return FALSE; }
/** * spice_channel_disconnect: * @channel: * @reason: a channel event emitted on main context (or #SPICE_CHANNEL_NONE) * * Close the socket and reset connection specific data. Finally, emit * @reason #SpiceChannel::channel-event on main context if not * #SPICE_CHANNEL_NONE. **/ void spice_channel_disconnect(SpiceChannel *channel, SpiceChannelEvent reason) { spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); g_return_if_fail(c != NULL); if (c->state == SPICE_CHANNEL_STATE_UNCONNECTED) return; if (reason == SPICE_CHANNEL_SWITCHING) c->state = SPICE_CHANNEL_STATE_SWITCHING; c->has_error = TRUE; /* break the loop */ if (c->state == SPICE_CHANNEL_STATE_MIGRATING) { c->state = SPICE_CHANNEL_STATE_READY; coroutine_yieldto(&c->coroutine, NULL); } else spice_channel_wakeup(channel); if (reason != SPICE_CHANNEL_NONE) { g_signal_emit(G_OBJECT(channel), signals[SPICE_CHANNEL_EVENT], 0, reason); } }
static void test_coroutine_simple(void) { struct coroutine *self = coroutine_self(); struct coroutine co = { .stack_size = 16 << 20, .entry = co_entry_42, }; gpointer result; g_assert(coroutine_self_is_main()); coroutine_init(&co); result = coroutine_yieldto(&co, GINT_TO_POINTER(42)); g_assert_cmpint(GPOINTER_TO_INT(result), ==, 0x42); g_test_expect_message(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*!to->exited*"); coroutine_yieldto(&co, GINT_TO_POINTER(42)); g_test_assert_expected_messages(); g_assert(self == coroutine_self()); g_assert(coroutine_self_is_main()); } static gpointer co_entry_two(gpointer data) { struct coroutine *self = coroutine_self(); struct coroutine co = { .stack_size = 16 << 20, .entry = co_entry_check_self, }; g_assert(!coroutine_self_is_main()); coroutine_init(&co); coroutine_yieldto(&co, &co); g_assert(self == coroutine_self()); return NULL; } static void test_coroutine_two(void) { struct coroutine *self = coroutine_self(); struct coroutine co = { .stack_size = 16 << 20, .entry = co_entry_two, }; coroutine_init(&co); coroutine_yieldto(&co, NULL); g_assert(self == coroutine_self()); } static gpointer co_entry_yield(gpointer data) { gpointer val; g_assert(data == NULL); val = coroutine_yield(GINT_TO_POINTER(1)); g_assert_cmpint(GPOINTER_TO_INT(val), ==, 2); g_assert(!coroutine_self_is_main()); val = coroutine_yield(GINT_TO_POINTER(3)); g_assert_cmpint(GPOINTER_TO_INT(val), ==, 4); return NULL; } static void test_coroutine_yield(void) { struct coroutine *self = coroutine_self(); struct coroutine co = { .stack_size = 16 << 20, .entry = co_entry_yield, }; gpointer val; coroutine_init(&co); val = coroutine_yieldto(&co, NULL); g_assert(self == coroutine_self()); g_assert_cmpint(GPOINTER_TO_INT(val), ==, 1); val = coroutine_yieldto(&co, GINT_TO_POINTER(2)); g_assert(self == coroutine_self()); g_assert_cmpint(GPOINTER_TO_INT(val), ==, 3); val = coroutine_yieldto(&co, GINT_TO_POINTER(4)); g_assert(self == coroutine_self()); g_assert(val == NULL); g_test_expect_message(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*!to->exited*"); coroutine_yieldto(&co, GINT_TO_POINTER(42)); g_test_assert_expected_messages(); } int main(int argc, char* argv[]) { g_test_init(&argc, &argv, NULL); g_test_add_func("/coroutine/simple", test_coroutine_simple); g_test_add_func("/coroutine/two", test_coroutine_two); g_test_add_func("/coroutine/yield", test_coroutine_yield); return g_test_run (); }