dbproxy-main函数

main主函数

/home/id/lua.lua
/home/id/lua-c/lua.lua
/home/id/lua-c/metatable.lua
/home/id/lua-c/1.lua

 

int main(int argc, char **argv) {
    return main_cmdline(argc, argv);
}
main_cmdline函数
int main_cmdline(int argc, char **argv) {
    //设置底盘的选项
    opts = chassis_options_new();
    chassis_frontend_set_chassis_options(frontend, opts);
    main_entries = chassis_options_to_g_option_entries(opts);

    //srcchassis-keyfile.c
    chassis_keyfile_to_options(frontend->keyfile, "mysql-proxy", main_entries)

    //srcmysql-proxy-cli.c
    //得到用户输入的/usr/local/wm/mysql-proxy/bin/mysql-proxy --defaults-file=/usr/local/wm/mysql-proxy/conf/source_wtf.cnf
    //中的defaults-file
    if (chassis_frontend_init_base_options(option_ctx, &argc, &argv, &(frontend->print_version), &(frontend->default_file), &gerr)) {

    }

    if (frontend->default_file) {
        if (!(frontend->keyfile = chassis_frontend_open_config_file(frontend->default_file, &gerr))) {
            g_log_dbproxy(g_critical, "loading config from '%s' failed: %s", frontend->default_file, gerr->message);
            exit;
        }
    }
    //得到defaults-file中的参数
    if (frontend->keyfile) {
        if (chassis_keyfile_to_options(frontend->keyfile, "mysql-proxy", main_entries)) {
            GOTO_EXIT(EXIT_FAILURE);
        }
    }

    //加载插件
    if (chassis_frontend_load_plugins(srv->modules, frontend->plugin_dir, frontend->plugin_names)) {
    
    }

    //初始化插件选项
    chassis_frontend_init_plugins(srv->modules, option_ctx, &argc, &argv, frontend->keyfile, "mysql-proxy", srv->base_dir, &gerr)) {

    }
    
    //启动多个线程, 并设置回调函数chassis_event_handle, 使用libevent
    if (chassis_mainloop(srv)) {
        /* looks like we failed */
        g_log_dbproxy(g_critical, "Failure from chassis_mainloop. Shutting down");
        exit;
    }
}

 

chassis_options_new
位置:srcchassis-options.c

/**
 * create a command-line option
 */
chassis_options_t *chassis_options_new() {
    chassis_options_t *opt;

    opt = g_slice_new0(chassis_options_t);

    return opt;
}

chassis_frontend_set_chassis_options
位置:srcmysql-proxy-cli.c

/**
 * setup the options of the chassis
 */
int chassis_frontend_set_chassis_options(chassis_frontend_t *frontend, chassis_options_t *opts) {
    chassis_options_add(opts, "verbose-shutdown", 0, 0, G_OPTION_ARG_NONE, &(frontend->verbose_shutdown), "Always log the exit code when shutting down", NULL, NULL, NULL, 0);
}

chassis_options_add
位置:srcchassis-options.c

int chassis_options_add(chassis_options_t *opts, 
        const char *long_name,
        gchar short_name,
        gint flags,
        GOptionArg arg,
        gpointer   arg_data,
        const char *description,
        const char *arg_description,
        chas_opt_assign_hook assign_hook,
        chas_opt_show_hook show_hook,
        gint opt_property) {
    chassis_option_t *opt;

    opt = chassis_option_new();
    if (0 != chassis_option_set(opt,
            long_name,
            short_name,
            flags,
            arg,
            arg_data,
            description,
            arg_description,
            assign_hook,
            show_hook,
            opt_property) ||
        0 != chassis_options_add_option(opts, opt)) {
        chassis_option_free(opt);
        return -1;
    } else {
        return 0;
    }
}

chassis_option_set
位置:srcchassis-options.c

/**
 * add a option
 *
 * GOptionEntry
 */
int chassis_option_set(chassis_option_t *opt, 
        const char *long_name,
        gchar short_name,
        gint flags,
        GOptionArg arg,
        gpointer   arg_data,
        const char *description,
        const char *arg_description,
        chas_opt_assign_hook assign_hook,
        chas_opt_show_hook show_hook,
        gint opt_property) {
    opt->long_name       = g_strdup(long_name);
    opt->short_name      = short_name;
    opt->flags           = flags;
    opt->arg             = arg;
    opt->arg_data        = arg_data;
    opt->description     = g_strdup(description);
    opt->arg_description = g_strdup(arg_description);
    opt->assign_opts_hook = assign_hook;
    opt->show_hook       = show_hook;
    opt->opt_property    = opt_property;

    return 0;
}

chassis_options_add_option
位置:srcchassis-options.c

/**
 * add a option
 *
 * GOptionEntry
 */
int chassis_options_add_option(chassis_options_t *opts, 
        chassis_option_t *opt) {

    opts->options = g_list_append(opts->options, opt);

    return 0;
}

chassis_options_to_g_option_entries
位置:srcchassis-options.c

/**
 * convert the chassis_options into a GOptionEntry
 *
 * @see chassis_options_free_g_option_entries
 */
GOptionEntry *chassis_options_to_g_option_entries(chassis_options_t *opts) {
    GOptionEntry *entries;
    int count;
    GList *node;

    /* build the GOptionEntry block */
    for (node = opts->options, count = 0; node; node = node->next) {
        count++;
    }

    entries = g_new0(GOptionEntry, count + 1);
    for (node = opts->options, count = 0; node; node = node->next) {
        chassis_option_t *opt = node->data;

        entries[count].long_name       = g_strdup(opt->long_name);
        entries[count].short_name      = opt->short_name;
        entries[count].flags           = opt->flags;
        entries[count].arg             = opt->arg;
        entries[count].arg_data        = opt->arg_data;
        entries[count].description     = g_strdup(opt->description);
        entries[count].arg_description = g_strdup(opt->arg_description);
        count++;
    }

    entries[count].long_name       = NULL;
    entries[count].short_name      = 0;
    entries[count].flags           = 0;
    entries[count].arg             = 0;
    entries[count].arg_data        = NULL;
    entries[count].description     = NULL;
    entries[count].arg_description = NULL;

    return entries;
}

chassis_keyfile_to_options
位置:srcchassis-keyfile.c

int chassis_keyfile_to_options(GKeyFile* keyfile, const gchar *ini_group_name, GOptionEntry *config_entries) {
    GError *gerr = NULL;
    int ret = 0;
    int i, j;
    
    /* all the options are in the group for "mysql-proxy" */

    if (!keyfile) return -1;
    if (!g_key_file_has_group(keyfile, ini_group_name)) return 0;

    /* set the defaults */
    for (i = 0; config_entries[i].long_name; i++) {
        GOptionEntry *entry = &(config_entries[i]);
        gchar *arg_string;
        gchar **arg_string_array;
        gboolean arg_bool = 0;
        gint arg_int = 0;
        gdouble arg_double = 0;
        gsize len = 0;

        switch (entry->arg) {
        case G_OPTION_ARG_FILENAME:
        case G_OPTION_ARG_STRING: 
            /* is this option set already */
            if (NULL == entry->arg_data || NULL != *(gchar **)(entry->arg_data)) break;

            arg_string = g_key_file_get_string(keyfile, ini_group_name, entry->long_name, &gerr);
            if (!gerr) {
                /* strip trailing spaces */
                *(gchar **)(entry->arg_data) = g_strchomp(arg_string);
            }
            break;
        case G_OPTION_ARG_FILENAME_ARRAY:
        case G_OPTION_ARG_STRING_ARRAY: 
            /* is this option set already */
            if (NULL == entry->arg_data || NULL != *(gchar ***)(entry->arg_data)) break;

            arg_string_array = g_key_file_get_string_list(keyfile, ini_group_name, entry->long_name, &len, &gerr);
            if (!gerr) {
                for (j = 0; arg_string_array[j]; j++) {
                    arg_string_array[j] = g_strstrip(arg_string_array[j]);
                }   
                *(gchar ***)(entry->arg_data) = arg_string_array;
            }
            break;
        case G_OPTION_ARG_NONE: 
            arg_bool = g_key_file_get_boolean(keyfile, ini_group_name, entry->long_name, &gerr);
            if (!gerr) {
                *(int *)(entry->arg_data) = arg_bool;
            }
            break;
        case G_OPTION_ARG_INT: 
            arg_int = g_key_file_get_integer(keyfile, ini_group_name, entry->long_name, &gerr);
            if (!gerr) {
                *(gint *)(entry->arg_data) = arg_int;
            }
            break;
#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 12 
        case G_OPTION_ARG_DOUBLE: 
            arg_double = g_key_file_get_double(keyfile, ini_group_name, entry->long_name, &gerr);
            if (!gerr) {
                *(gdouble *)(entry->arg_data) = arg_double;
            }
            break;
#endif
        default:
            g_log_dbproxy(g_error, "(keyfile) the option %d can't be handled", entry->arg);
            break;
        }

        if (gerr) {
            if (gerr->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
                g_log_dbproxy(g_critical, "%s", gerr->message);
                ret = -1;
            }

            g_error_free(gerr);
            gerr = NULL;
        }
    }

    return ret;
}

chassis_frontend_init_base_options
位置:srcchassis-frontend.c

int chassis_frontend_init_base_options(GOptionContext *option_ctx,
        int *argc_p, char ***argv_p,
        int *print_version,
        char **config_file,
        GError **gerr) {
    chassis_options_t *opts;
    GOptionEntry *base_main_entries;
    int ret = 0;

    opts = chassis_options_new();
    chassis_options_set_cmdline_only_options(opts, print_version, config_file);
    base_main_entries = chassis_options_to_g_option_entries(opts);

    g_option_context_add_main_entries(option_ctx, base_main_entries, NULL);
    g_option_context_set_help_enabled(option_ctx, FALSE);
    g_option_context_set_ignore_unknown_options(option_ctx, TRUE);

    if (FALSE == g_option_context_parse(option_ctx, argc_p, argv_p, gerr)) {
        ret = -1;
    }

    /* do not use chassis_options_free_g_options... here, we need to hang on to the data until the end of the program! */
    chassis_frontend_options_free(base_main_entries);

    chassis_options_free(opts);

    return ret;
}

chassis_options_set_cmdline_only_options
位置: srcchassis-frontend.c

/**
 * setup the options that can only appear on the command-line
 */
int chassis_options_set_cmdline_only_options(chassis_options_t *opts,
        int *print_version,
        char **config_file) {

    chassis_options_add(opts,
        "version", 'V', 0, G_OPTION_ARG_NONE, print_version, "Show version", NULL, NULL, NULL, 0);

    chassis_options_add(opts,
        "defaults-file", 0, 0, G_OPTION_ARG_STRING, config_file, "configuration file", "<file>", NULL, NULL, 0);

    return 0;
}

chassis_frontend_init_plugins
位置:srcchassis-frontend.c

int chassis_frontend_init_plugins(GPtrArray *plugins,
        GOptionContext *option_ctx,
        int *argc_p, char ***argv_p,
        GKeyFile *keyfile,
        const char* keyfile_section_name,
        const char *base_dir,
        GError **gerr) {
    guint i;

    for (i = 0; i < plugins->len; i++) {
        GOptionEntry *config_entries = NULL;
        chassis_plugin *p = plugins->pdata[i];
        chassis_options_t *plugin_opts = NULL;

        if (NULL != (plugin_opts = chassis_plugin_get_options(p))) {
            gchar *group_desc = g_strdup_printf("%s-module", p->option_grp_name);
            gchar *help_msg = g_strdup_printf("Show options for the %s-module", p->option_grp_name);
            const gchar *group_name = p->option_grp_name;

            config_entries = chassis_options_to_g_option_entries(plugin_opts);

            GOptionGroup *option_grp = g_option_group_new(group_name, group_desc, help_msg, NULL, NULL);
            g_option_group_add_entries(option_grp, config_entries);
            g_option_context_add_group(option_ctx, option_grp);

            g_free(help_msg);
            g_free(group_desc);

            /* parse the new options */
            if (FALSE == g_option_context_parse(option_ctx, argc_p, argv_p, gerr)) {
                return -1;
            }
    
            if (keyfile) {
                if (chassis_keyfile_to_options(keyfile, keyfile_section_name, config_entries)) {
                    return -1;
                }
            }

            /* resolve the path names for these config entries */
            chassis_keyfile_resolve_path(base_dir, config_entries); 
        }

        if (config_entries != NULL) {
            chassis_frontend_options_free(config_entries);
        }
    }



    return 0;
}

chassis_plugin_get_options
位置:srcchassis-plugin.c

chassis_options_t* chassis_plugin_get_options(chassis_plugin *p) {
    chassis_options_t * options;

    if (!p->get_options) return NULL;

    if (NULL == (options = p->get_options(p->config))) {
        g_log_dbproxy(g_critical, "adding config options for module '%s' failed", p->name);
    }

    return options;
}

chassis_frontend_load_plugins
位置srcchassis-frontend.c

int chassis_frontend_load_plugins(GPtrArray *plugins, const gchar *plugin_dir, gchar **plugin_names) {
    int i;

    /* load the plugins */
    for (i = 0; plugin_names && plugin_names[i]; i++) {
        chassis_plugin *p;

        char *plugin_filename;
        /* skip trying to load a plugin when the parameter was --plugins= 
           that will never work...
        */
        if (!g_strcmp0("", plugin_names[i])) {
            continue;
        }

        plugin_filename = g_strdup_printf("%s%c%s%s.%s", 
                plugin_dir, 
                G_DIR_SEPARATOR, 
                G_MODULE_PREFIX,
                plugin_names[i],
                SHARED_LIBRARY_SUFFIX);

        p = chassis_plugin_load(plugin_filename);
        g_free(plugin_filename);

        if (NULL == p) {
            g_log_dbproxy(g_critical, "setting --plugin-dir=<dir> might help");
            return -1;
        }
        p->option_grp_name = g_strdup(plugin_names[i]);

        g_ptr_array_add(plugins, p);
    }
    return 0;
}

chassis_plugin_load
位置:srcchassis-plugin.c

chassis_plugin* chassis_plugin_load(const gchar *name) {
    int (*plugin_init)(chassis_plugin *p);
    chassis_plugin *p = chassis_plugin_new();

    p->module = g_module_open(name, G_MODULE_BIND_LOCAL);

    if (!p->module) {
        g_log_dbproxy(g_critical, "loading module '%s' failed: %s", name, g_module_error());

        chassis_plugin_free(p);

        return NULL;
    }

    /* each module has to have a plugin_init function */
    if (!g_module_symbol(p->module, "plugin_init", (gpointer) &plugin_init)) {
        g_log_dbproxy(g_critical, "module '%s' doesn't have a init-function: %s", name, g_module_error());
        chassis_plugin_free(p);
        return NULL;
    }

    if (0 != plugin_init(p)) {
        g_log_dbproxy(g_critical, "init-function for module '%s' failed", name);
        chassis_plugin_free(p);
        return NULL;
    }

    if (p->magic != CHASSIS_PLUGIN_MAGIC) {
        g_log_dbproxy(g_critical, "plugin '%s' doesn't match the current plugin interface (plugin is %lx, chassis is %lx)", name, p->magic, CHASSIS_PLUGIN_MAGIC);
        chassis_plugin_free(p);
        return NULL;
    }

    if (p->init) {
        p->config = p->init();
    }

    /* if the plugins haven't set p->name provide our own name */
    if (!p->name) p->name = g_strdup(name);
    /* set dummy version number if the plugin doesn't provide a real one */
    if (!p->version) {
        g_log_dbproxy(g_critical, "plugin '%s' doesn't set a version number, refusing to load this plugin", name);
        chassis_plugin_free(p);
        return NULL;
    }
    
    if (p->new_stats) {
        p->stats = p->new_stats();
    }

    return p;
}

plugin_init
位置:pluginsproxyproxy-plugin.c

G_MODULE_EXPORT int plugin_init(chassis_plugin *p) {
    p->magic        = CHASSIS_PLUGIN_MAGIC;
    p->name         = g_strdup("proxy");
    p->version  = g_strdup(PACKAGE_VERSION);

    p->init         = network_mysqld_proxy_plugin_new;
    p->get_options  = network_mysqld_proxy_plugin_get_options;
    p->apply_config = network_mysqld_proxy_plugin_apply_config;
    p->destroy      = network_mysqld_proxy_plugin_free;

    return 0;
}

network_mysqld_proxy_plugin_new
位置:pluginsproxyproxy-plugin.c

//全局变量
chassis_plugin_config *config = NULL;

chassis_plugin_config * network_mysqld_proxy_plugin_new(void) {
    config = g_new0(chassis_plugin_config, 1);

    config->fix_bug_25371   = 0; /** double ERR packet on AUTH failures */
    config->profiling       = 1;
    config->start_proxy     = 1;
    config->pool_change_user = 1; /* issue a COM_CHANGE_USER to cleanup the connection 
                     when we get back the connection from the pool */
    config->dt_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)dt_table_free);

    config->select_where_limit_str = NULL;
    config->select_where_limit = SEL_OFF;
    config->charset = NULL;

    config->opts = NULL;

    config->percentile_value = 64;

    config->check_state_conn_timeout = 3;
    config->check_state_interval = PROXY_CHECK_STATE_WAIT_TIMEOUT;
    config->check_state_retry_times = RETRY_TIMES;
    config->check_state_sleep_delay = SLEEP_DELAY;
    g_rw_lock_init(&config->config_lock);

    config->sql_log_mgr = sql_log_t_new();
    config->percentile_controller = pt_percentile_new(6.0, 29.0, 2);

    config->plugin_threads = g_hash_table_new_full(g_str_hash,
                                         g_str_equal,
                                         g_free,
                                         (GDestroyNotify)plugin_thread_t_free);
    config->table_prefix = NULL;
    config->table_suffix = NULL;
    config->tnw = tbl_name_wrap_new();

    return config;
}

network_mysqld_proxy_plugin_get_options
位置:pluginsproxyproxy-plugin.c

设置插件的选项
我们更改的id-generate 就在这里
需要在

1)config增加新的属性id-generate
./plugins/proxy/proxy-plugin.h
struct chassis_plugin_config {
    ...
    gchar* id_generate;
};
2)初始化
./plugins/proxy/proxy-plugin.c
chassis_plugin_config * network_mysqld_proxy_plugin_new(void) {
    ...
    config->id_generate = NULL;
    return config;
}
static chassis_options_t * network_mysqld_proxy_plugin_get_options(chassis_plugin_config *oldconfig) {
    if (config->opts == NULL) {
        chassis_options_t *opts = chassis_options_new();

        chassis_options_add(opts, "proxy-address",            'P', 0, G_OPTION_ARG_STRING, &(config->address), "listening address:port of the proxy-server (default: :4040)", "<host:port>",
                            NULL, show_proxy_address, SHOW_OPTS_PROPERTY);
    chassis_options_add(opts, "id-generate", 0, 0, G_OPTION_ARG_STRING, &(config->id_generate), "Run mysql-proxy as user", NULL, NULL, NULL, 0);
    
     config->opts = opts;
    }
        
    return config->opts;
}

chassis_mainloop
位置:srcchassis-mainloop.c

int chassis_mainloop(void *_chas) {
    chassis *chas = _chas;
    guint i;
    struct event ev_sigterm, ev_sigint;
#ifdef SIGHUP
    struct event ev_sighup;
#endif
    chassis_event_thread_t *mainloop_thread;

    /* redirect logging from libevent to glib */
    event_set_log_callback(event_log_use_glib);


    /* add a event-handler for the "main" events */
    mainloop_thread = chassis_event_thread_new(0);
    chassis_event_threads_init_thread(mainloop_thread, chas);
    g_ptr_array_add(chas->threads, mainloop_thread);

    chas->event_base = mainloop_thread->event_base; /* all global events go to the 1st thread */

    g_assert(chas->event_base);


    /* setup all plugins all plugins */
    for (i = 0; i < chas->modules->len; i++) {
        chassis_plugin *p = chas->modules->pdata[i];

        g_assert(p->apply_config);
        if (0 != p->apply_config(chas, p->config)) {
            g_log_dbproxy(g_critical, "applying config of plugin %s failed", p->name);
            return -1;
        }
    }

    signal_set(&ev_sigterm, SIGTERM, sigterm_handler, NULL);
    event_base_set(chas->event_base, &ev_sigterm);
    signal_add(&ev_sigterm, NULL);

    signal_set(&ev_sigint, SIGINT, sigint_handler, NULL);
    event_base_set(chas->event_base, &ev_sigint);
    signal_add(&ev_sigint, NULL);

#ifdef SIGHUP
    signal_set(&ev_sighup, SIGHUP, sighup_handler, chas);
    event_base_set(chas->event_base, &ev_sighup);
    if (signal_add(&ev_sighup, NULL)) {
        g_log_dbproxy(g_critical, "signal_add(SIGHUP) failed");
    }
#endif

    if (chas->event_thread_count < 1) chas->event_thread_count = 1;

    /* create the event-threads
     *
     * - dup the async-queue-ping-fds
     * - setup the events notification
     * */
    for (i = 1; i <= (guint)chas->event_thread_count; i++) { /* we already have 1 event-thread running, the main-thread */
        chassis_event_thread_t *thread = chassis_event_thread_new(i);

        chassis_event_threads_init_thread(thread, chas);

        g_ptr_array_add(chas->threads, thread);
    }

    /* start the event threads */
    chassis_event_threads_start(chas->threads);

    /**
     * handle signals and all basic events into the main-thread
     *
     * block until we are asked to shutdown
     */
    chassis_mainloop_thread_loop(mainloop_thread);

    signal_del(&ev_sigterm);
    signal_del(&ev_sigint);
#ifdef SIGHUP
    signal_del(&ev_sighup);
#endif
    return 0;
}

chassis_event_thread_new
位置:srcchassis-event-thread.c

/**
 * create the data structure for a new event-thread
 */
chassis_event_thread_t* chassis_event_thread_new(guint index) {
    chassis_event_thread_t *thread = g_new0(chassis_event_thread_t, 1);

    thread->index = index;

    thread->event_queue = g_async_queue_new();

    g_rw_lock_init(&thread->connection_lock);
    thread->connection_list = NULL;

    thread->exit_phase = EVENT_THREAD_NORMAL;
    return thread;
}

chassis_event_threads_init_thread
位置:srcchassis-event-thread.c

/**
 * setup the notification-fd of a event-thread
 *
 * all event-threads listen on the same notification pipe
 *
 * @see chassis_event_handle()
 */ 
int chassis_event_threads_init_thread(chassis_event_thread_t *thread, chassis *chas) {
    thread->event_base = event_base_new();
    thread->chas = chas;

    int fds[2];
    if (pipe(fds)) {
        int err;
        err = errno;
        g_log_dbproxy(g_error, "evutil_socketpair() failed: %s (%d)",  g_strerror(err), err);
    }
    thread->notify_receive_fd = fds[0];
    thread->notify_send_fd = fds[1];

    event_set(&(thread->notify_fd_event), thread->notify_receive_fd, EV_READ | EV_PERSIST, chassis_event_handle, thread);
    event_base_set(thread->event_base, &(thread->notify_fd_event));
    event_add(&(thread->notify_fd_event), NULL);

    return 0;
}

chassis_event_threads_start
位置:srcchassis-event-thread.c

/**
 * start all the event-threads 
 *
 * starts all the event-threads that got added by chassis_event_threads_add()
 *
 * @see chassis_event_threads_add
 */
void chassis_event_threads_start(GPtrArray *threads) {
    guint i;

    g_log_dbproxy(g_message, "starting %d threads", threads->len - 1);

    for (i = 1; i < threads->len; i++) { /* the 1st is the main-thread and already set up */
        chassis_event_thread_t *thread = threads->pdata[i];
        GError *gerr = NULL;

        thread->thr = g_thread_try_new("event thread", (GThreadFunc)chassis_event_thread_loop, thread, &gerr);
        if (gerr) {
            g_log_dbproxy(g_critical, "%s", gerr->message);
            g_error_free(gerr);
            gerr = NULL;
        }
    }
}

chassis_mainloop_thread_loop
位置:srcchassis-event-thread.c

/**
 * event-handler thread
 *
 */
void* chassis_mainloop_thread_loop(chassis_event_thread_t *thread) {
    cur_thid = thread->index;
    gboolean is_all_work_thread_exit = FALSE;
    g_assert(thread->index == 0);

    /**
     * check once a second if we shall shutdown the proxy
     */
    while (!chassis_is_shutdown() || !is_all_work_thread_exit) {
        struct timeval timeout;
        int r;

        timeout.tv_sec = 1;
        timeout.tv_usec = 0;

        g_assert(event_base_loopexit(thread->event_base, &timeout) == 0);

        r = event_base_dispatch(thread->event_base);

        if (r == -1) {
            if (errno == EINTR) continue;
            g_log_dbproxy(g_critical, "leaving chassis_event_thread_loop early, errno != EINTR was: %s (%d)", g_strerror(errno), errno);
            break;
        }

        if (chassis_is_shutdown()) {
                gint i = 1;
                for (; i < thread->chas->threads->len; i++) {
                    chassis_event_thread_t *event_thread = g_ptr_array_index(thread->chas->threads, i);
                    if (g_atomic_int_get(&event_thread->exit_phase) != EVENT_THREAD_EXITED) break;
                }
                if (i == thread->chas->threads->len) {
                    is_all_work_thread_exit = TRUE;
                }
            }
    }

    g_log_dbproxy(g_message, "main loop thread will exit");

    return NULL;
}
原文地址:https://www.cnblogs.com/taek/p/8344960.html