File:  [Qemu by Fabrice Bellard] / qemu / test-coroutine.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:17:02 2018 UTC (3 years, 1 month ago) by root
Branches: qemu, MAIN
CVS tags: qemu1001, HEAD
qemu 1.0.1

    1: /*
    2:  * Coroutine tests
    3:  *
    4:  * Copyright IBM, Corp. 2011
    5:  *
    6:  * Authors:
    7:  *  Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
    8:  *
    9:  * This work is licensed under the terms of the GNU LGPL, version 2 or later.
   10:  * See the COPYING.LIB file in the top-level directory.
   11:  *
   12:  */
   13: 
   14: #include <glib.h>
   15: #include "qemu-coroutine.h"
   16: 
   17: /*
   18:  * Check that qemu_in_coroutine() works
   19:  */
   20: 
   21: static void coroutine_fn verify_in_coroutine(void *opaque)
   22: {
   23:     g_assert(qemu_in_coroutine());
   24: }
   25: 
   26: static void test_in_coroutine(void)
   27: {
   28:     Coroutine *coroutine;
   29: 
   30:     g_assert(!qemu_in_coroutine());
   31: 
   32:     coroutine = qemu_coroutine_create(verify_in_coroutine);
   33:     qemu_coroutine_enter(coroutine, NULL);
   34: }
   35: 
   36: /*
   37:  * Check that qemu_coroutine_self() works
   38:  */
   39: 
   40: static void coroutine_fn verify_self(void *opaque)
   41: {
   42:     g_assert(qemu_coroutine_self() == opaque);
   43: }
   44: 
   45: static void test_self(void)
   46: {
   47:     Coroutine *coroutine;
   48: 
   49:     coroutine = qemu_coroutine_create(verify_self);
   50:     qemu_coroutine_enter(coroutine, coroutine);
   51: }
   52: 
   53: /*
   54:  * Check that coroutines may nest multiple levels
   55:  */
   56: 
   57: typedef struct {
   58:     unsigned int n_enter;   /* num coroutines entered */
   59:     unsigned int n_return;  /* num coroutines returned */
   60:     unsigned int max;       /* maximum level of nesting */
   61: } NestData;
   62: 
   63: static void coroutine_fn nest(void *opaque)
   64: {
   65:     NestData *nd = opaque;
   66: 
   67:     nd->n_enter++;
   68: 
   69:     if (nd->n_enter < nd->max) {
   70:         Coroutine *child;
   71: 
   72:         child = qemu_coroutine_create(nest);
   73:         qemu_coroutine_enter(child, nd);
   74:     }
   75: 
   76:     nd->n_return++;
   77: }
   78: 
   79: static void test_nesting(void)
   80: {
   81:     Coroutine *root;
   82:     NestData nd = {
   83:         .n_enter  = 0,
   84:         .n_return = 0,
   85:         .max      = 128,
   86:     };
   87: 
   88:     root = qemu_coroutine_create(nest);
   89:     qemu_coroutine_enter(root, &nd);
   90: 
   91:     /* Must enter and return from max nesting level */
   92:     g_assert_cmpint(nd.n_enter, ==, nd.max);
   93:     g_assert_cmpint(nd.n_return, ==, nd.max);
   94: }
   95: 
   96: /*
   97:  * Check that yield/enter transfer control correctly
   98:  */
   99: 
  100: static void coroutine_fn yield_5_times(void *opaque)
  101: {
  102:     bool *done = opaque;
  103:     int i;
  104: 
  105:     for (i = 0; i < 5; i++) {
  106:         qemu_coroutine_yield();
  107:     }
  108:     *done = true;
  109: }
  110: 
  111: static void test_yield(void)
  112: {
  113:     Coroutine *coroutine;
  114:     bool done = false;
  115:     int i = -1; /* one extra time to return from coroutine */
  116: 
  117:     coroutine = qemu_coroutine_create(yield_5_times);
  118:     while (!done) {
  119:         qemu_coroutine_enter(coroutine, &done);
  120:         i++;
  121:     }
  122:     g_assert_cmpint(i, ==, 5); /* coroutine must yield 5 times */
  123: }
  124: 
  125: /*
  126:  * Check that creation, enter, and return work
  127:  */
  128: 
  129: static void coroutine_fn set_and_exit(void *opaque)
  130: {
  131:     bool *done = opaque;
  132: 
  133:     *done = true;
  134: }
  135: 
  136: static void test_lifecycle(void)
  137: {
  138:     Coroutine *coroutine;
  139:     bool done = false;
  140: 
  141:     /* Create, enter, and return from coroutine */
  142:     coroutine = qemu_coroutine_create(set_and_exit);
  143:     qemu_coroutine_enter(coroutine, &done);
  144:     g_assert(done); /* expect done to be true (first time) */
  145: 
  146:     /* Repeat to check that no state affects this test */
  147:     done = false;
  148:     coroutine = qemu_coroutine_create(set_and_exit);
  149:     qemu_coroutine_enter(coroutine, &done);
  150:     g_assert(done); /* expect done to be true (second time) */
  151: }
  152: 
  153: /*
  154:  * Lifecycle benchmark
  155:  */
  156: 
  157: static void coroutine_fn empty_coroutine(void *opaque)
  158: {
  159:     /* Do nothing */
  160: }
  161: 
  162: static void perf_lifecycle(void)
  163: {
  164:     Coroutine *coroutine;
  165:     unsigned int i, max;
  166:     double duration;
  167: 
  168:     max = 1000000;
  169: 
  170:     g_test_timer_start();
  171:     for (i = 0; i < max; i++) {
  172:         coroutine = qemu_coroutine_create(empty_coroutine);
  173:         qemu_coroutine_enter(coroutine, NULL);
  174:     }
  175:     duration = g_test_timer_elapsed();
  176: 
  177:     g_test_message("Lifecycle %u iterations: %f s\n", max, duration);
  178: }
  179: 
  180: int main(int argc, char **argv)
  181: {
  182:     g_test_init(&argc, &argv, NULL);
  183:     g_test_add_func("/basic/lifecycle", test_lifecycle);
  184:     g_test_add_func("/basic/yield", test_yield);
  185:     g_test_add_func("/basic/nesting", test_nesting);
  186:     g_test_add_func("/basic/self", test_self);
  187:     g_test_add_func("/basic/in_coroutine", test_in_coroutine);
  188:     if (g_test_perf()) {
  189:         g_test_add_func("/perf/lifecycle", perf_lifecycle);
  190:     }
  191:     return g_test_run();
  192: }

unix.superglobalmegacorp.com