static gboolean test_force_set(void) { GThread *th; amsemaphore_t *sem = amsemaphore_new_with_value(10); th = g_thread_create(test_force_set_thread, (gpointer)sem, TRUE, NULL); /* sleep to give amsemaphore_decrement() a chance to block (or not). */ g_usleep(G_USEC_PER_SEC / 4); /* set it to 30, so decrement can proceed, but leave the value at 10 */ amsemaphore_force_set(sem, 30); /* sleep to give amsemaphore_wait_empty() a chance to block (or not). */ g_usleep(G_USEC_PER_SEC / 4); /* and empty out the semaphore */ amsemaphore_force_set(sem, 0); g_thread_join(th); amsemaphore_free(sem); /* it we didn't hang yet, it's all good */ return TRUE; }
static gboolean test_decr_wait(void) { GThread *th; struct test_decr_wait_data data = { NULL, FALSE }; int rv; data.sem = amsemaphore_new_with_value(10), th = g_thread_create(test_decr_wait_thread, (gpointer)&data, TRUE, NULL); /* sleep to give amsemaphore_decrement() a chance to block (or not). */ g_usleep(G_USEC_PER_SEC / 4); /* and then increment the semaphore enough that the decrement can succeed */ data.increment_called = TRUE; amsemaphore_increment(data.sem, 10); /* join the thread and see how it fared. */ rv = GPOINTER_TO_INT(g_thread_join(th)); amsemaphore_free(data.sem); return (rv == 1); }
static gboolean test_wait_empty(void) { GThread *th; amsemaphore_t *sem = amsemaphore_new_with_value(10); int rv; th = g_thread_create(test_wait_empty_thread, (gpointer)sem, TRUE, NULL); /* sleep to give amsemaphore_decrement() a chance to block (or not). */ g_usleep(G_USEC_PER_SEC / 4); /* add another 10, so decrement can hit zero next time it's called */ amsemaphore_increment(sem, 10); /* and wait on the semaphore emptying */ amsemaphore_wait_empty(sem); /* join the thread and see how it fared. */ rv = GPOINTER_TO_INT(g_thread_join(th)); amsemaphore_free(sem); return (rv == 1); }
static gboolean setup_impl( XferElement *elt) { XferElementGlue *self = (XferElementGlue *)elt; gboolean need_ring = FALSE; gboolean need_listen_input = FALSE; gboolean need_listen_output = FALSE; g_assert(elt->input_mech != XFER_MECH_NONE); g_assert(elt->output_mech != XFER_MECH_NONE); g_assert(elt->input_mech != elt->output_mech); self->read_fdp = NULL; self->write_fdp = NULL; self->on_push = PUSH_INVALID; self->on_pull = PULL_INVALID; self->need_thread = FALSE; switch (mech_pair(elt->input_mech, elt->output_mech)) { case mech_pair(XFER_MECH_READFD, XFER_MECH_WRITEFD): /* thread will read from one fd and write to the other */ self->read_fdp = &neighboring_element_fd; self->write_fdp = &neighboring_element_fd; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_READFD, XFER_MECH_PUSH_BUFFER): /* thread will read from one fd and call push_buffer downstream */ self->read_fdp = &neighboring_element_fd; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_READFD, XFER_MECH_PULL_BUFFER): self->read_fdp = &neighboring_element_fd; self->on_pull = PULL_FROM_FD; break; case mech_pair(XFER_MECH_READFD, XFER_MECH_DIRECTTCP_LISTEN): /* thread will connect for output, then read from fd and write to the * socket. */ self->read_fdp = &neighboring_element_fd; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_READFD, XFER_MECH_DIRECTTCP_CONNECT): /* thread will accept output conn, then read from upstream and write to socket */ self->read_fdp = &neighboring_element_fd; self->need_thread = TRUE; need_listen_output = TRUE; break; case mech_pair(XFER_MECH_WRITEFD, XFER_MECH_READFD): make_pipe(self); g_assert(xfer_element_swap_input_fd(elt, self->pipe[1]) == -1); self->pipe[1] = -1; /* upstream will close this for us */ g_assert(xfer_element_swap_output_fd(elt, self->pipe[0]) == -1); self->pipe[0] = -1; /* downstream will close this for us */ break; case mech_pair(XFER_MECH_WRITEFD, XFER_MECH_PUSH_BUFFER): /* thread will read from pipe and call downstream's push_buffer */ make_pipe(self); g_assert(xfer_element_swap_input_fd(elt, self->pipe[1]) == -1); self->pipe[1] = -1; /* upstream will close this for us */ self->read_fdp = &self->pipe[0]; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_WRITEFD, XFER_MECH_PULL_BUFFER): make_pipe(self); g_assert(xfer_element_swap_input_fd(elt, self->pipe[1]) == -1); self->pipe[1] = -1; /* upstream will close this for us */ self->on_pull = PULL_FROM_FD; self->read_fdp = &self->pipe[0]; break; case mech_pair(XFER_MECH_WRITEFD, XFER_MECH_DIRECTTCP_LISTEN): /* thread will connect for output, then read from pipe and write to socket */ make_pipe(self); g_assert(xfer_element_swap_input_fd(elt, self->pipe[1]) == -1); self->pipe[1] = -1; /* upstream will close this for us */ self->read_fdp = &self->pipe[0]; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_WRITEFD, XFER_MECH_DIRECTTCP_CONNECT): /* thread will accept output conn, then read from pipe and write to socket */ make_pipe(self); g_assert(xfer_element_swap_input_fd(elt, self->pipe[1]) == -1); self->pipe[1] = -1; /* upstream will close this for us */ self->read_fdp = &self->pipe[0]; self->need_thread = TRUE; need_listen_output = TRUE; break; case mech_pair(XFER_MECH_PUSH_BUFFER, XFER_MECH_READFD): make_pipe(self); g_assert(xfer_element_swap_output_fd(elt, self->pipe[0]) == -1); self->pipe[0] = -1; /* downstream will close this for us */ self->on_push = PUSH_TO_FD; self->write_fdp = &self->pipe[1]; break; case mech_pair(XFER_MECH_PUSH_BUFFER, XFER_MECH_WRITEFD): self->on_push = PUSH_TO_FD; self->write_fdp = &neighboring_element_fd; break; case mech_pair(XFER_MECH_PUSH_BUFFER, XFER_MECH_PULL_BUFFER): self->on_push = PUSH_TO_RING_BUFFER; self->on_pull = PULL_FROM_RING_BUFFER; need_ring = TRUE; break; case mech_pair(XFER_MECH_PUSH_BUFFER, XFER_MECH_DIRECTTCP_LISTEN): /* push will connect for output first */ self->on_push = PUSH_TO_FD | PUSH_CONNECT_FIRST; break; case mech_pair(XFER_MECH_PUSH_BUFFER, XFER_MECH_DIRECTTCP_CONNECT): /* push will accept for output first */ self->on_push = PUSH_TO_FD | PUSH_ACCEPT_FIRST; need_listen_output = TRUE; break; case mech_pair(XFER_MECH_PULL_BUFFER, XFER_MECH_READFD): /* thread will pull from upstream and write to pipe */ make_pipe(self); g_assert(xfer_element_swap_output_fd(elt, self->pipe[0]) == -1); self->pipe[0] = -1; /* downstream will close this for us */ self->write_fdp = &self->pipe[1]; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_PULL_BUFFER, XFER_MECH_WRITEFD): /* thread will pull from upstream and write to downstream */ self->write_fdp = &neighboring_element_fd; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_PULL_BUFFER, XFER_MECH_PUSH_BUFFER): /* thread will pull from upstream and push to downstream */ self->need_thread = TRUE; break; case mech_pair(XFER_MECH_PULL_BUFFER, XFER_MECH_DIRECTTCP_LISTEN): /* thread will connect for output, then pull from upstream and write to socket */ self->need_thread = TRUE; break; case mech_pair(XFER_MECH_PULL_BUFFER, XFER_MECH_DIRECTTCP_CONNECT): /* thread will accept for output, then pull from upstream and write to socket */ self->need_thread = TRUE; need_listen_output = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_LISTEN, XFER_MECH_READFD): /* thread will accept for input, then read from socket and write to pipe */ make_pipe(self); g_assert(xfer_element_swap_output_fd(elt, self->pipe[0]) == -1); self->pipe[0] = -1; /* downstream will close this for us */ self->write_fdp = &self->pipe[1]; self->need_thread = TRUE; need_listen_input = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_LISTEN, XFER_MECH_WRITEFD): /* thread will accept for input, then read from socket and write to downstream */ self->write_fdp = &neighboring_element_fd; self->need_thread = TRUE; need_listen_input = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_LISTEN, XFER_MECH_PUSH_BUFFER): /* thread will accept for input, then read from socket and push downstream */ self->need_thread = TRUE; need_listen_input = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_LISTEN, XFER_MECH_PULL_BUFFER): /* first pull will accept for input, then read from socket */ self->on_pull = PULL_FROM_FD | PULL_ACCEPT_FIRST; need_listen_input = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_LISTEN, XFER_MECH_DIRECTTCP_CONNECT): /* thread will accept on both sides, then copy from socket to socket */ self->need_thread = TRUE; need_listen_input = TRUE; need_listen_output = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_CONNECT, XFER_MECH_READFD): /* thread will connect for input, then read from socket and write to pipe */ make_pipe(self); g_assert(xfer_element_swap_output_fd(elt, self->pipe[0]) == -1); self->pipe[0] = -1; /* downstream will close this for us */ self->write_fdp = &self->pipe[1]; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_CONNECT, XFER_MECH_WRITEFD): /* thread will connect for input, then read from socket and write to downstream */ self->write_fdp = &neighboring_element_fd; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_CONNECT, XFER_MECH_PUSH_BUFFER): /* thread will connect for input, then read from socket and push downstream */ self->need_thread = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_CONNECT, XFER_MECH_PULL_BUFFER): /* first pull will connect for input, then read from socket */ self->on_pull = PULL_FROM_FD | PULL_CONNECT_FIRST; break; case mech_pair(XFER_MECH_DIRECTTCP_CONNECT, XFER_MECH_DIRECTTCP_LISTEN): /* thread will connect on both sides, then copy from socket to socket */ self->on_pull = PULL_FROM_FD | PULL_ACCEPT_FIRST; self->need_thread = TRUE; break; default: g_assert_not_reached(); break; } /* set up ring if desired */ if (need_ring) { self->ring = g_try_malloc(sizeof(*self->ring) * GLUE_RING_BUFFER_SIZE); if (self->ring == NULL) { xfer_cancel_with_error(elt, "Can't allocate memory for ring"); return FALSE; } self->ring_used_sem = amsemaphore_new_with_value(0); self->ring_free_sem = amsemaphore_new_with_value(GLUE_RING_BUFFER_SIZE); } if (need_listen_input) { if (!do_directtcp_listen(elt, &self->input_listen_socket, &elt->input_listen_addrs)) return FALSE; } if (need_listen_output) { if (!do_directtcp_listen(elt, &self->output_listen_socket, &elt->output_listen_addrs)) return FALSE; } return TRUE; }