Chris Smowton <cs448@cam.ac.uk>:
...whenever I tried
to start a trace using the GUI, it would freeze consuming 100% CPU after
I clicked "start". Turned out this was because in tracecontrol.c's
start_clicked callback, you poll(2) on an FD and use a switch()
statement to handle its return.
Unfortunately, poll(2) doesn't work that way -- it returns a *mask* of
bits, not a single value. Here poll was returning POLLIN | POLLHUP to
indicate there's data ready and the FD has been closed by the other
side, and since this != POLLIN and != POLLHUP, the poll loop spins
forever.
Attached is a patch to be applied to tracecontrol.c which fixes it to
check for set-bits instead. It's still strictly broken, as the read(fd,
buf, 256) call might not fully drain the child's output, but it's a step
in the right direction and means I can at least use the trace-control
thing.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
/* Timeout : Stop waiting for chars */
if(num_rdy == 0) goto wait_child;
/* Timeout : Stop waiting for chars */
if(num_rdy == 0) goto wait_child;
- switch(pollfd.revents) {
- case POLLERR:
+ /* Check for fatal errors */
+ if(pollfd.revents & POLLERR) {
g_warning("Error returned in polling fd\n");
num_hup++;
g_warning("Error returned in polling fd\n");
num_hup++;
- break;
- case POLLHUP:
- g_info("Polling FD : hung up.");
- num_hup++;
- break;
- case POLLNVAL:
- g_warning("Polling fd tells it is not open");
- num_hup++;
- break;
- case POLLPRI:
- case POLLIN:
- count = read (fdpty, buf, 256);
- if(count > 0) {
- unsigned int i;
- buf[count] = '\0';
- g_printf("%s", buf);
- for(i=0; i<count; i++) {
- switch(read_state) {
- case GET_LINE:
- if(buf[i] == '\n') {
- read_state = GET_SEMI;
- g_debug("Tracecontrol input line skip\n");
- }
- break;
- case GET_SEMI:
- if(buf[i] == ':') {
- g_debug("Tracecontrol input : marker found\n");
- read_state = GET_SPACE;
- }
- break;
- case GET_SPACE:
- if(buf[i] == ' ') {
- g_debug("Tracecontrol input space marker found\n");
- goto write_password;
- }
- break;
- }
- }
- } else if(count == -1) {
- perror("Error in read");
- goto wait_child;
- }
- break;
+ if(pollfd.revents & POLLNVAL) {
+ g_warning("Polling fd tells it is not open");
+ num_hup++;
+ }
+
+ if(pollfd.revents & POLLHUP) {
+
+ g_info("Polling FD : hung up.");
+ num_hup++;
+
+ }
+
+ if(pollfd.revents & (POLLIN | POLLPRI)) {
+ int count;
+ count = read (fdpty, buf, 256);
+ if(count > 0) {
+ unsigned int i;
+ buf[count] = '\0';
+ g_printf("%s", buf);
+ for(i=0; i<count; i++) {
+ switch(read_state) {
+ case GET_LINE:
+ if(buf[i] == '\n') {
+ read_state = GET_SEMI;
+ g_debug("Tracecontrol input line skip\n");
+ }
+ break;
+ case GET_SEMI:
+ if(buf[i] == ':') {
+ g_debug("Tracecontrol input : marker found\n");
+ read_state = GET_SPACE;
+ }
+ break;
+ case GET_SPACE:
+ if(buf[i] == ' ') {
+ g_debug("Tracecontrol input space marker found\n");
+ goto write_password;
+ }
+ break;
+ }
+ }
+ } else if(count == -1) {
+ perror("Error in read");
+ goto wait_child;
+ }
+
+ }
+
- g_warning("Child hung up too fast");
+ g_warning("Child hung up without returning a full reply");