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);
    }
}
Beispiel #3
0
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 ();
}