tshark: Run GLib mainloop during capture

Use the timer polling approach on Windows. GLib timer callbacks execute
in main thread. Remove useless mutex as there is no point in protecting
resources if only can thread can access the resources. Simply wait on
capture child handle instead of periodically checking process state.

On Unix systems, register the pipe fd for polling inside GLib mainloop.
This commit is contained in:
Tomasz Moń 2022-07-28 19:20:32 +02:00 committed by Gerald Combs
parent 0816e317cb
commit df7f3e76b5
2 changed files with 23 additions and 87 deletions

View File

@ -2028,11 +2028,6 @@ signal_pipe_capquit_to_child(capture_session *cap_session)
void
sync_pipe_stop(capture_session *cap_session)
{
#ifdef _WIN32
int count;
DWORD childstatus;
gboolean terminate = TRUE;
#endif
if (cap_session->fork_child != WS_INVALID_PID) {
#ifndef _WIN32
/* send the SIGINT signal to close the capture child gracefully. */
@ -2042,24 +2037,18 @@ sync_pipe_stop(capture_session *cap_session)
}
#else
#define STOP_SLEEP_TIME 500 /* ms */
#define STOP_CHECK_TIME 50
DWORD status;
/* First, use the special signal pipe to try to close the capture child
* gracefully.
*/
signal_pipe_capquit_to_child(cap_session);
/* Next, wait for the process to exit on its own */
for (count = 0; count < STOP_SLEEP_TIME / STOP_CHECK_TIME; count++) {
if (GetExitCodeProcess((HANDLE) cap_session->fork_child, &childstatus) &&
childstatus != STILL_ACTIVE) {
terminate = FALSE;
break;
}
Sleep(STOP_CHECK_TIME);
}
status = WaitForSingleObject((HANDLE) cap_session->fork_child, STOP_SLEEP_TIME);
/* Force the issue. */
if (terminate) {
if (status != WAIT_OBJECT_0) {
ws_warning("sync_pipe_stop: forcing child to exit");
sync_pipe_kill(cap_session->fork_child);
}

View File

@ -30,6 +30,7 @@
#ifndef _WIN32
#include <signal.h>
#include <glib-unix.h>
#endif
#include <glib.h>
@ -2498,14 +2499,8 @@ clean_exit:
return exit_status;
}
/*#define USE_BROKEN_G_MAIN_LOOP*/
#ifdef USE_BROKEN_G_MAIN_LOOP
GMainLoop *loop;
#else
gboolean loop_running = FALSE;
#endif
guint32 packet_count = 0;
gboolean loop_running = FALSE;
guint32 packet_count = 0;
typedef struct pipe_input_tag {
@ -2514,9 +2509,6 @@ typedef struct pipe_input_tag {
ws_process_id *child_process;
pipe_input_cb_t input_cb;
guint pipe_input_id;
#ifdef _WIN32
GMutex *callback_running;
#endif
} pipe_input_t;
static pipe_input_t pipe_input;
@ -2534,8 +2526,6 @@ pipe_timer_cb(gpointer data)
pipe_input_t *pipe_input_p = data;
gint iterations = 0;
g_mutex_lock (pipe_input_p->callback_running);
/* try to read data from the pipe only 5 times, to avoid blocking */
while(iterations < 5) {
/* Oddly enough although Named pipes don't work on win9x,
@ -2555,9 +2545,8 @@ pipe_timer_cb(gpointer data)
/* And call the real handler */
if (!pipe_input_p->input_cb(pipe_input_p->source, pipe_input_p->user_data)) {
ws_debug("input pipe closed, iterations: %u", iterations);
/* pipe closed, return false so that the timer is stopped */
g_mutex_unlock (pipe_input_p->callback_running);
return FALSE;
/* pipe closed, stop the timer */
return G_SOURCE_REMOVE;
}
}
else {
@ -2568,14 +2557,18 @@ pipe_timer_cb(gpointer data)
iterations++;
}
g_mutex_unlock (pipe_input_p->callback_running);
/* we didn't stopped the timer, so let it run */
return TRUE;
return G_SOURCE_CONTINUE;
}
#else
static gboolean
pipe_fd_cb(gint fd _U_, GIOCondition condition _U_, gpointer user_data)
{
pipe_input_t *pipe_input_p = (pipe_input_t *)user_data;
return pipe_input_p->input_cb(pipe_input_p->source, pipe_input_p->user_data);
}
#endif
void
pipe_input_set_handler(gint source, gpointer user_data, ws_process_id *child_process, pipe_input_cb_t input_cb)
{
@ -2586,14 +2579,14 @@ pipe_input_set_handler(gint source, gpointer user_data, ws_process_id *child_pro
pipe_input.input_cb = input_cb;
#ifdef _WIN32
pipe_input.callback_running = g_new(GMutex, 1);
g_mutex_init(pipe_input.callback_running);
/* Tricky to use pipes in win9x, as no concept of wait. NT can
do this but that doesn't cover all win32 platforms. GTK can do
this but doesn't seem to work over processes. Attempt to do
something similar here, start a timer and check for data on every
timeout. */
pipe_input.pipe_input_id = g_timeout_add(200, pipe_timer_cb, &pipe_input);
#else
pipe_input.pipe_input_id = g_unix_fd_add(source, G_IO_IN | G_IO_HUP, pipe_fd_cb, &pipe_input);
#endif
}
@ -2638,9 +2631,7 @@ capture(void)
volatile gboolean ret = TRUE;
guint i;
GString *str;
#ifdef USE_TSHARK_SELECT
fd_set readfds;
#endif
GMainContext *ctx;
#ifndef _WIN32
struct sigaction action, oldaction;
#endif
@ -2714,54 +2705,15 @@ capture(void)
*/
set_resolution_synchrony(TRUE);
/* the actual capture loop
*
* XXX - glib doesn't seem to provide any event based loop handling.
*
* XXX - for whatever reason,
* calling g_main_loop_new() ends up in 100% cpu load.
*
* But that doesn't matter: in UNIX we can use select() to find an input
* source with something to do.
*
* But that doesn't matter because we're in a CLI (that doesn't need to
* update a GUI or something at the same time) so it's OK if we block
* trying to read from the pipe.
*
* So all the stuff in USE_TSHARK_SELECT could be removed unless I'm
* wrong (but I leave it there in case I am...).
*/
#ifdef USE_TSHARK_SELECT
FD_ZERO(&readfds);
FD_SET(pipe_input.source, &readfds);
#endif
/* the actual capture loop */
ctx = g_main_context_default();
loop_running = TRUE;
TRY
{
while (loop_running)
{
#ifdef USE_TSHARK_SELECT
ret = select(pipe_input.source+1, &readfds, NULL, NULL, NULL);
if (ret == -1)
{
fprintf(stderr, "%s: %s\n", "select()", g_strerror(errno));
ret = TRUE;
loop_running = FALSE;
} else if (ret == 1) {
#endif
/* Call the real handler */
if (!pipe_input.input_cb(pipe_input.source, pipe_input.user_data)) {
ws_debug("input pipe closed");
ret = FALSE;
loop_running = FALSE;
}
#ifdef USE_TSHARK_SELECT
}
#endif
g_main_context_iteration(ctx, TRUE);
}
}
CATCH(OutOfMemoryError) {
@ -3076,12 +3028,7 @@ capture_input_closed(capture_session *cap_session _U_, gchar *msg)
report_counts();
#ifdef USE_BROKEN_G_MAIN_LOOP
/*g_main_loop_quit(loop);*/
g_main_loop_quit(loop);
#else
loop_running = FALSE;
#endif
}
#ifdef _WIN32