barbieri pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=b79f03c916a54b41d401c5464ce2af9faa06b972
commit b79f03c916a54b41d401c5464ce2af9faa06b972 Author: Gustavo Sverzut Barbieri <[email protected]> Date: Thu Nov 24 18:46:51 2016 -0200 efl_debug (client): rewrite using efl_net. Rewrite and greatly improve error checking, allow multiple commands to be given in series, etc. This also leverages on Efl.Io.Queue to buffer data for us, then all we need to do is peek at its contents, when there is a full message we use and then ask the queue to discard it. The CLST processing was also rewritten to not allocate memory. Since memory may be unaligned we still iterate over the buffer and memcpy() to an integer to avoid alignment errors. --- src/bin/efl/efl_debug.c | 414 +++++++++++++++++++++++++++++++---------- src/bin/efl/efl_debug_common.h | 15 +- 2 files changed, 317 insertions(+), 112 deletions(-) diff --git a/src/bin/efl/efl_debug.c b/src/bin/efl/efl_debug.c index f27504d..594aba6 100644 --- a/src/bin/efl/efl_debug.c +++ b/src/bin/efl/efl_debug.c @@ -16,150 +16,360 @@ * if not, see <http://www.gnu.org/licenses/>. */ +#define EFL_BETA_API_SUPPORT 1 +#define EFL_EO_API_SUPPORT 1 #include "efl_debug_common.h" -static unsigned char *buf; -static unsigned int buf_size; +static Eo *dialer; +static Eo *input; +static Eo *output; +static Eo *send_copier; +static Eo *recv_copier; -static int my_argc; -static char **my_argv; -static const char *expect = NULL; +static Eina_List *waiting; -static Ecore_Con_Server *svr; +static int retval = EXIT_SUCCESS; + +static const char CLST[4] = "CLST"; static void -_do(char *op, unsigned char *d, int size) +_process_reply(const char op[static 4], const Eina_Slice payload) { - if (!strcmp(op, "CLST")) +#define IS_OP(x) memcmp(op, x, 4) == 0 + + if (IS_OP(CLST)) { - int i, n; + int mypid = getpid(); + size_t offset; - n = (size) / sizeof(int); - if (n < 10000) + waiting = eina_list_remove(waiting, CLST); + + for (offset = 0; offset + sizeof(int) <= payload.len; offset += sizeof(int)) { - int *pids = malloc(n * sizeof(int)); - if (pids) - { - int mypid = getpid(); - memcpy(pids, d, n * sizeof(int)); - for (i = 0; i < n; i++) - { - if (pids[i] == mypid) continue; - if (pids[i] > 0) printf("%i\n", pids[i]); - } - free(pids); - } + int p; + + memcpy(&p, payload.bytes + offset, sizeof(int)); + + if (p == mypid) continue; + if (p > 0) printf("%i\n", p); } } - if ((expect) && (!strcmp(op, expect))) ecore_main_loop_quit(); + else + { + fprintf(stderr, "ERROR: unexpected server reply: %.4s\n", op); + retval = EXIT_FAILURE; + } + + if (!waiting) ecore_main_loop_quit(); + +#undef IS_OP } -Eina_Bool -_server_add(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_Con_Event_Server_Add *ev EINA_UNUSED) +static void +_on_data(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED) { - int i; - for (i = 1; i < my_argc; i++) + Eina_Slice slice, payload; + Efl_Debug_Message_Header msgheader; + + if (!efl_io_queue_slice_get(output, &slice)) + return; + + if (slice.len < sizeof(msgheader)) + return; + + memcpy(&msgheader, slice.mem, sizeof(msgheader)); + if (msgheader.size < 4) /* must contain at last 4 byte opcode */ { - if (!strcmp(my_argv[i], "list")) - { - send_svr(svr, "LIST", NULL, 0); - expect = "CLST"; - } - else if ((!strcmp(my_argv[i], "pon")) && - (i < (my_argc - 2))) - { - unsigned char tmp[8]; - int pid = atoi(my_argv[i + 1]); - unsigned int freq = atoi(my_argv[i + 2]); - i += 2; - store_val(tmp, 0, pid); - store_val(tmp, 4, freq); - send_svr(svr, "PLON", tmp, sizeof(tmp)); - ecore_main_loop_quit(); - } - else if ((!strcmp(my_argv[i], "poff")) && - (i < (my_argc - 1))) - { - unsigned char tmp[4]; - int pid = atoi(my_argv[i + 1]); - i++; - store_val(tmp, 0, pid); - send_svr(svr, "PLOF", tmp, sizeof(tmp)); - ecore_main_loop_quit(); - } - else if ((!strcmp(my_argv[i], "evlogon")) && - (i < (my_argc - 1))) - { - unsigned char tmp[4]; - int pid = atoi(my_argv[i + 1]); - i++; - store_val(tmp, 0, pid); - send_svr(svr, "EVON", tmp, sizeof(tmp)); - ecore_main_loop_quit(); - } - else if ((!strcmp(my_argv[i], "evlogoff")) && - (i < (my_argc - 1))) - { - unsigned char tmp[4]; - int pid = atoi(my_argv[i + 1]); - i++; - store_val(tmp, 0, pid); - send_svr(svr, "EVOF", tmp, sizeof(tmp)); - ecore_main_loop_quit(); - } + fprintf(stderr, "ERROR: invalid message header, size=%u\n", msgheader.size); + retval = EXIT_FAILURE; + ecore_main_loop_quit(); + return; } - return ECORE_CALLBACK_RENEW; -} -Eina_Bool -_server_del(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_Con_Event_Server_Del *ev EINA_UNUSED) -{ - ecore_main_loop_quit(); - return ECORE_CALLBACK_RENEW; + if (msgheader.size + 4 > slice.len) + return; + + payload.bytes = slice.bytes + sizeof(msgheader); + payload.len = msgheader.size - 4; + + _process_reply(msgheader.op, payload); + + efl_io_queue_discard(output, sizeof(msgheader) + payload.len); } static Eina_Bool -_server_data(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_Con_Event_Server_Data *ev) +_command_send(const char op[static 4], const void *data, unsigned int len) { - char op[5]; - unsigned char *d = NULL; - int size; + Eina_Error err; + Efl_Debug_Message_Header msghdr = { + .size = 4 + len, + }; + Eina_Slice s, r; + + memcpy(msghdr.op, op, 4); + + s.mem = &msghdr; + s.len = sizeof(msghdr); + + err = efl_io_writer_write(input, &s, &r); + if (err || r.len) goto end; + + if (!len) goto end; - _protocol_collect(&(buf), &(buf_size), ev->data, ev->size); - while ((size = _proto_read(&(buf), &(buf_size), op, &d)) >= 0) + s.mem = data; + s.len = len; + err = efl_io_writer_write(input, &s, &r); + + end: + if (err) + { + fprintf(stderr, "ERROR: could not queue message '%.4s': %s\n", op, eina_error_msg_get(err)); + retval = EXIT_FAILURE; + return EINA_FALSE; + } + + if (r.len) { - _do(op, d, size); - free(d); - d = NULL; + fprintf(stderr, "ERROR: could not queue message '%.4s': out of memory\n", op); + retval = EXIT_FAILURE; + return EINA_FALSE; } - return ECORE_CALLBACK_RENEW; + + return EINA_TRUE; +} + +static void +_dialer_eos(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED) +{ + ecore_main_loop_quit(); +} + +static void +_dialer_error(void *data EINA_UNUSED, const Efl_Event *event) +{ + Eina_Error *perr = event->info; + + fprintf(stderr, "ERROR: error communicating to %s: %s\n", + efl_net_dialer_address_dial_get(dialer), + eina_error_msg_get(*perr)); + retval = EINA_TRUE; + ecore_main_loop_quit(); } int main(int argc, char **argv) { + Eo *loop; + char *path; + Eina_Error err; + int i; + + if (argc < 2) + { + fprintf(stderr, "ERROR: missing argument.\n"); + return EXIT_FAILURE; + } + for (i = 1; i < argc; i++) + { + if ((strcmp(argv[i], "-h") != 0) && + (strcmp(argv[i], "--help") != 0)) + continue; + + printf("Usage:\n" + "\n" + "\t%s <command> [arguments]\n" + "\n" + "where <command> is one of:\n" + "\tlist list connected process (pid)\n" + "\tpon <pid> <freq> enable profiling for <pid> at frequency <freq> in microseconds.\n" + "\tpoff <pid> disable profiling for <pid>\n" + "\tevlogon <pid> start logging events to ~/efl_debug_evlog-<pid>.log\n" + "\tevlogoff <pid> stop logging events from <pid>\n", + argv[0]); + + return EXIT_SUCCESS; + } + + ecore_app_no_system_modules(); + eina_init(); ecore_init(); ecore_con_init(); - my_argc = argc; - my_argv = argv; + path = ecore_con_local_path_new(EINA_FALSE, "efl_debug", 0); + if (!path) + { + fprintf(stderr, "ERROR: could not get local communication path\n"); + retval = EXIT_FAILURE; + goto end; + } + + loop = ecore_main_loop_get(); + +#ifdef EFL_NET_DIALER_UNIX_CLASS + dialer = efl_add(EFL_NET_DIALER_UNIX_CLASS, loop); +#else + /* TODO: maybe start a TCP using locahost:12345? + * Right now eina_debug_monitor is only for AF_UNIX, so not an issue. + */ + fprintf(stderr, "ERROR: your platform doesn't support Efl.Net.Dialer.Unix\n"); +#endif + if (!dialer) + { + fprintf(stderr, "ERROR: could not create communication dialer\n"); + retval = EXIT_FAILURE; + goto end; + } + efl_event_callback_add(dialer, EFL_NET_DIALER_EVENT_ERROR, _dialer_error, NULL); + efl_event_callback_add(dialer, EFL_IO_READER_EVENT_EOS, _dialer_eos, NULL); + + input = efl_add(EFL_IO_QUEUE_CLASS, loop); + if (!input) + { + fprintf(stderr, "ERROR: could not create input queue\n"); + retval = EXIT_FAILURE; + goto end; + } + + output = efl_add(EFL_IO_QUEUE_CLASS, loop, + efl_event_callback_add(efl_added, EFL_IO_QUEUE_EVENT_SLICE_CHANGED, _on_data, NULL)); + if (!output) + { + fprintf(stderr, "ERROR: could not create output queue\n"); + retval = EXIT_FAILURE; + goto end; + } + + send_copier = efl_add(EFL_IO_COPIER_CLASS, loop, + efl_io_copier_source_set(efl_added, input), + efl_io_copier_destination_set(efl_added, dialer), + efl_io_closer_close_on_destructor_set(efl_added, EINA_FALSE)); + if (!send_copier) + { + fprintf(stderr, "ERROR: could not create send copier\n"); + retval = EXIT_FAILURE; + goto end; + } + + recv_copier = efl_add(EFL_IO_COPIER_CLASS, loop, + efl_io_copier_source_set(efl_added, dialer), + efl_io_copier_destination_set(efl_added, output), + efl_io_closer_close_on_destructor_set(efl_added, EINA_FALSE)); + if (!recv_copier) + { + fprintf(stderr, "ERROR: could not create receive copier\n"); + retval = EXIT_FAILURE; + goto end; + } - svr = ecore_con_server_connect(ECORE_CON_LOCAL_USER, "efl_debug", 0, NULL); - if (!svr) + for (i = 1; i < argc; i++) { - fprintf(stderr, "ERROR: Cannot connect to debug daemon.\n"); - return -1; + const char *cmd = argv[i]; + + if (strcmp(cmd, "list") == 0) + { + if (!_command_send("LIST", NULL, 0)) + goto end; + waiting = eina_list_append(waiting, CLST); + } + else if (strcmp(cmd, "pon") == 0) + { + if (i + 2 >= argc) + { + fprintf(stderr, "ERROR: missing argument: pon <pid> <freq>\n"); + retval = EXIT_FAILURE; + goto end; + } + else + { + int data[2] = {atoi(argv[i + 1]), atoi(argv[1 + 2])}; + if (!_command_send("PLON", data, sizeof(data))) + goto end; + i += 2; + } + } + else if (strcmp(cmd, "poff") == 0) + { + if (i + 1 >= argc) + { + fprintf(stderr, "ERROR: missing argument: poff <pid>\n"); + retval = EXIT_FAILURE; + goto end; + } + else + { + int data[1] = {atoi(argv[i + 1])}; + if (!_command_send("PLOFF", data, sizeof(data))) + goto end; + i++; + } + } + else if (strcmp(cmd, "evlogon") == 0) + { + if (i + 1 >= argc) + { + fprintf(stderr, "ERROR: missing argument: evlogon <pid>\n"); + retval = EXIT_FAILURE; + goto end; + } + else + { + int data[1] = {atoi(argv[i + 1])}; + if (!_command_send("EVON", data, sizeof(data))) + goto end; + i++; + } + } + else if (strcmp(cmd, "evlogoff") == 0) + { + if (i + 1 >= argc) + { + fprintf(stderr, "ERROR: missing argument: evlogoff <pid>\n"); + retval = EXIT_FAILURE; + goto end; + } + else + { + int data[1] = {atoi(argv[i + 1])}; + if (!_command_send("EVOF", data, sizeof(data))) + goto end; + i++; + } + } + else + { + fprintf(stderr, "ERROR: unknown command: %s\n", argv[i]); + retval = EXIT_FAILURE; + goto end; + } } + efl_io_queue_eos_mark(input); - ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, (Ecore_Event_Handler_Cb)_server_add, NULL); - ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, (Ecore_Event_Handler_Cb)_server_del, NULL); - ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA, (Ecore_Event_Handler_Cb)_server_data, NULL); + err = efl_net_dialer_dial(dialer, path); + if (err) + { + fprintf(stderr, "ERROR: could not connect '%s': %s\n", path, eina_error_msg_get(err)); + retval = EXIT_FAILURE; + goto end; + } ecore_main_loop_begin(); - ecore_con_server_flush(svr); + + while ((!efl_io_closer_closed_get(dialer)) && + efl_io_queue_usage_get(input)) + efl_io_copier_flush(send_copier); + + end: + eina_list_free(waiting); + efl_del(input); + efl_del(output); + efl_del(dialer); + efl_del(send_copier); + efl_del(recv_copier); + free(path); ecore_con_shutdown(); ecore_shutdown(); eina_shutdown(); + return retval; } diff --git a/src/bin/efl/efl_debug_common.h b/src/bin/efl/efl_debug_common.h index dc6190e..29e9739 100644 --- a/src/bin/efl/efl_debug_common.h +++ b/src/bin/efl/efl_debug_common.h @@ -27,6 +27,11 @@ #include <unistd.h> #include <string.h> +typedef struct _Efl_Debug_Message_Header { + unsigned int size; + char op[4]; +} Efl_Debug_Message_Header; + void _protocol_collect(unsigned char **buf, unsigned int *buf_size, void *data, int size); int _proto_read(unsigned char **buf, unsigned int *buf_size, @@ -36,16 +41,6 @@ int _proto_read(unsigned char **buf, unsigned int *buf_size, memcpy(&dst, ((unsigned char *)buf) + off, sizeof(dst)) #define store_val(buf, off, src) \ memcpy(buf + off, &src, sizeof(src)) -#define send_svr(svr, op, data, size) \ - do { \ - unsigned char head[8]; \ - char *op2 = op; \ - int size2 = size + 4; \ - memcpy(head + 0, &size2, 4); \ - memcpy(head + 4, op2, 4); \ - ecore_con_server_send(svr, head, 8); \ - if (size > 0) ecore_con_server_send(svr, data, size); \ - } while (0) #define send_cli(cli, op, data, size) \ do { \ unsigned char head[8]; \ --
