server.c 4.39 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/*
 * (C) 2015 The University of Chicago
 * 
 * See COPYRIGHT in top-level directory.
 */

#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <abt.h>
Philip Carns's avatar
Philip Carns committed
11 12
#include <abt-snoozer.h>
#include <margo.h>
13 14 15 16 17 18 19 20 21 22

#include "my-rpc.h"

/* example server program.  Starts HG engine, registers the example RPC type,
 * and then executes indefinitely.
 */

int main(int argc, char **argv) 
{
    int ret;
23
    margo_instance_id mid;
24 25 26 27
    ABT_xstream handler_xstream;
    ABT_pool handler_pool;
    ABT_xstream progress_xstream;
    ABT_pool progress_pool;
28 29
    hg_context_t *hg_context;
    hg_class_t *hg_class;
30
    int single_pool_mode = 0;
31
    
32
    if(argc > 3 || argc < 2)
33
    {
34
        fprintf(stderr, "Usage: ./server <listen_addr> <single>\n");
35 36 37 38
        fprintf(stderr, "   Note: the optional \"single\" argument makes the server use a single ABT pool for both HG progress and RPC handlers.\n");
        return(-1);
    }

39
    if(argc == 3)
40
    {
41
        if(strcmp(argv[2], "single") == 0)
42 43 44
            single_pool_mode = 1;
        else
        {
45
            fprintf(stderr, "Usage: ./server <listen_addr> <single>\n");
46 47 48 49 50
            fprintf(stderr, "   Note: the optional \"single\" argument makes the server use a single ABT pool for both HG progress and RPC handlers.\n");
            return(-1);
        }
    }

51
    /* boilerplate HG initialization steps */
52
    /***************************************/
53
    hg_class = HG_Init(argv[1], HG_TRUE);
54 55 56 57 58 59 60 61 62 63 64 65 66 67
    if(!hg_class)
    {
        fprintf(stderr, "Error: HG_Init()\n");
        return(-1);
    }
    hg_context = HG_Context_create(hg_class);
    if(!hg_context)
    {
        fprintf(stderr, "Error: HG_Context_create()\n");
        HG_Finalize(hg_class);
        return(-1);
    }

    /* set up argobots */
68
    /***************************************/
69 70 71 72 73 74 75
    ret = ABT_init(argc, argv);
    if(ret != 0)
    {
        fprintf(stderr, "Error: ABT_init()\n");
        return(-1);
    }

Philip Carns's avatar
Philip Carns committed
76 77
    /* set primary ES to idle without polling */
    ret = ABT_snoozer_xstream_self_set();
78 79
    if(ret != 0)
    {
Philip Carns's avatar
Philip Carns committed
80
        fprintf(stderr, "Error: ABT_snoozer_xstream_self_set()\n");
81 82 83
        return(-1);
    }

84 85 86 87 88 89 90 91 92 93 94 95 96 97
    /* Find primary pool to use for running rpc handlers */
    ret = ABT_xstream_self(&handler_xstream);
    if(ret != 0)
    {
        fprintf(stderr, "Error: ABT_xstream_self()\n");
        return(-1);
    }
    ret = ABT_xstream_get_main_pools(handler_xstream, 1, &handler_pool);
    if(ret != 0)
    {
        fprintf(stderr, "Error: ABT_xstream_get_main_pools()\n");
        return(-1);
    }

98
    if(!single_pool_mode)
99
    {
100 101 102 103 104 105 106
        /* create a dedicated ES drive Mercury progress */
        ret = ABT_snoozer_xstream_create(1, &progress_pool, &progress_xstream);
        if(ret != 0)
        {
            fprintf(stderr, "Error: ABT_snoozer_xstream_create()\n");
            return(-1);
        }
107 108
    }

109
    /* actually start margo */
110 111 112 113 114
    /* provide argobots pools for driving communication progress and
     * executing rpc handlers as well as class and context for Mercury
     * communication.
     */
    /***************************************/
115 116 117 118
    if(single_pool_mode)
        mid = margo_init(handler_pool, handler_pool, hg_context, hg_class);
    else
        mid = margo_init(progress_pool, handler_pool, hg_context, hg_class);
119
    assert(mid);
120 121

    /* register RPC */
122 123
    MERCURY_REGISTER(hg_class, "my_rpc", my_rpc_in_t, my_rpc_out_t, 
        my_rpc_ult_handler);
124 125
    MERCURY_REGISTER(hg_class, "my_shutdown_rpc", void, void, 
        my_rpc_shutdown_ult_handler);
126

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    /* NOTE: at this point this server ULT has two options.  It can wait on
     * whatever mechanism it wants to (however long the daemon should run and
     * then call margo_finalize().  Otherwise, it can call
     * margo_wait_for_finalize() on the assumption that it should block until
     * some other entity calls margo_finalize().
     *
     * This example does the latter.  Margo will be finalized by a special
     * RPC from the client.
     *
     * This approach will allow the server to idle gracefully even when
     * executed in "single" mode, in which the main thread of the server
     * daemon and the progress thread for Mercury are executing in the same
     * ABT pool.
     */
    margo_wait_for_finalize(mid);
142

143 144 145 146 147
    if(!single_pool_mode)
    {
        ABT_xstream_join(progress_xstream);
        ABT_xstream_free(&progress_xstream);
    }
148

149 150
    ABT_finalize();

151 152 153
    HG_Context_destroy(hg_context);
    HG_Finalize(hg_class);

154 155 156
    return(0);
}