Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Where to start debugging zle recursive-edit? / Ctrl-C



On 30 September 2016 at 22:44, Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
> Because you are in recursive-edit, interrupting does not go all they
> way back to the top-level prompt where the precmd hook would restore
> the timer, so it remains unscheduled until the current zle session
> is done and precmd runs again.

I'm looking at the outputs from some time today and what you say seems
to ring bells thinking what I observe but not yet clear. However, what
I do observe clearly is:

-- tmoutp != ZTM_NONE / raw_getbyte() zle_main.c
-- (**) NOT doing break selret[0] / zle_main.c: errflag: 0, retflag:
0, breaks: 0, exit_pending: 0
--  Passed !errtry(errtry:1) selret[0] / zle_main.c
## set errflag to 2 (ERRFLAG_INT:2) / signals.c

This means: SIGINT is received – select breaks. Then errflag is checked (**):

            if (selret < 0 && (errflag || retflag || breaks || exit_pending)) {
                fprintf( _F, "-- Doing break [selret:%d] / zle_main.c:
errflag: %d, retflag: %d, breaks: %d, exit_pending: %d\>
                            selret, errflag, retflag, breaks, exit_pending );
                break;
            } else {
                fprintf( _F, "-- NOT doing break selret[%d] /
zle_main.c: errflag: %d, retflag: %d, breaks: %d, exit_pending: >
                            selret, errflag, retflag, breaks, exit_pending );
            }

(fopen/fclose removed). Result: no break is done, no errflag to
trigger it. Then the check runs:

            if (selret < 0 && !errtry) {
                fprintf( _F, "-- Trying again selret[%d], !errtry[%d]
/ zle_main.c\n", selret, errtry );
                errtry = 1;
                continue;
            } else

And select is run again – .recedit ignores SIGNT, does not return.
This is the thing that I observe, multiple Ctrl-C to break out from
widget. After this zhandler() sets the errflag:

        if (!handletrap(SIGINT)) {
            if ((isset(PRIVILEGED) || isset(RESTRICTED)) &&
                isset(INTERACTIVE) && noerrexit < 0)
                zexit(SIGINT, 1);
            if (list_pipe || chline || simple_pline) {
                breaks = loops;
                errflag |= ERRFLAG_INT;
                inerrflush();
                check_cursh_sig(SIGINT);

                fprintf( _F, "## set errflag to %d (ERRFLAG_INT:%d) /
signals.c\n", errflag, ERRFLAG_INT );
            }

I wonder if this can result also in problems with rescheduling. Code
runs with errflag set and as you said this stops scheduled function
before any execution is done.

Can something be done to make zhandler() set errflag faster, or to
make the raw_getbyte's after-select() checks wait for zhandler's
resolution?

> You may need to find a more aggressive place to reset the timer, such
> as in the zle-line-pre-redraw hook, or else create a wrapper widget
> for recursive-edit.
>
> Either way you'd want to examine $zle_scheduled_events to see if the
> timer is still pending, before scheduling it again.

I use this trick:

ZCONVEY_SCHEDULE_ORIGIN="$SECONDS"
sched +"${ZCONVEY_CONFIG[check_interval]}" __zconvey_on_period_passed
"$ZCONVEY_SCHEDULE_ORIGIN"

Then inside the handler a check is done to make only the current
"*SCHEDULE_ORIGIN" do rescheduling. So I can quite freely
overschedule, in the end only last schedule goes int rescheduling
loop.

>
> Or possibly you could switch from doing this with a timer scheduled
> function to using a "zle -F" handler function.

Would be great to also have in 5.3 .recedit answering predictably to
Ctrl-C. What's also interesting is that I could not get setting
errflag late when not in .recedit. The logs always look like this:

-- tmoutp != ZTM_NONE / raw_getbyte() zle_main.c
## set errflag to 2 (ERRFLAG_INT:2) / signals.c
-- Doing break [selret:-1] / zle_main.c: errflag: 2, retflag: 0,
breaks: 0, exit_pending: 0
-- Got EINTR 3
-- Setting error in zlecore.c

Best regards,
Sebastian Gniazdowski
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 9a83d41..7bcf450 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -450,47 +450,87 @@ static void
 calc_timeout(struct ztmout *tmoutp, long do_keytmout)
 {
     if (do_keytmout && (keytimeout > 0 || do_keytmout < 0)) {
 	if (do_keytmout < 0)
 	    tmoutp->exp100ths = (time_t)-do_keytmout;
 	else if (keytimeout > ZMAXTIMEOUT * 100 /* 24 days for a keypress???? */)
 	    tmoutp->exp100ths = ZMAXTIMEOUT * 100;
 	else
 	    tmoutp->exp100ths = keytimeout;
 	tmoutp->tp = ZTM_KEY;
-    } else
+        // MY DEBUG
+        FILE *_F = fopen("/tmp/recursive.txt", "a+");
+        fprintf( _F, "-- tmoutp->tp <- ZTM_KEY (%d) / calc_timeout() zle_main.c\n", tmoutp->exp100ths );
+        fclose(_F);
+    } else {
+        // MY DEBUG
+        FILE *_F = fopen("/tmp/recursive.txt", "a+");
+        fprintf( _F, "-- tmoutp->tp <- ZTM_NONE / calc_timeout( do_keytmout: %d ), keytimeout: %d / zle_main.c\n", do_keytmout, keytimeout );
+        fclose(_F);
+
 	tmoutp->tp = ZTM_NONE;
+    }
 
     if (timedfns) {
+        // MY DEBUG
+        FILE *_F = fopen("/tmp/recursive.txt", "a+");
+        fprintf( _F, "== CALC_TIMEOUT() one more chance (timedfns exp100ths: %d)\n", tmoutp->exp100ths );
+        fclose(_F);
 	for (;;) {
 	    LinkNode tfnode = firstnode(timedfns);
 	    Timedfn tfdat;
 	    time_t diff, exp100ths;
 
-	    if (!tfnode)
+	    if (!tfnode) {
+                // MY DEBUG
+                FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                fprintf( _F, "-- CALC_TIMEOUT() !tfnode break\n" );
+                fclose(_F);
 		break;
+            }
 
 	    tfdat = (Timedfn)getdata(tfnode);
 	    diff = tfdat->when - time(NULL);
+
 	    if (diff < 0) {
+                // MY DEBUG
+                FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                fprintf( _F, "-- CALC_TIMEOUT() tfnode TRUE no break CALLING >> DIFF=%d <<\n", diff );
+                fclose(_F);
+
 		/* Already due; call it and rescan. */
 		tfdat->func();
 		continue;
-	    }
+	    } else {
+                // MY DEBUG
+                FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                fprintf( _F, "-- CALC_TIMEOUT() tfnode TRUE no break NOT calling >> DIFF=%d <<\n", diff );
+                fclose(_F);
+            }
 
 	    if (diff > ZMAXTIMEOUT) {
+                // MY DEBUG
+                FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                fprintf( _F, "-- CALC_TIMEOUT() %d > %d ZTM_MAX(%d)\n", diff, ZMAXTIMEOUT, ZTM_MAX );
+                fclose(_F);
+
 		tmoutp->exp100ths = ZMAXTIMEOUT * 100;
 		tmoutp->tp = ZTM_MAX;
-	    } else if (diff > 0) {
+	    } else if (diff >= 0) {
 		exp100ths = diff * 100;
 		if (tmoutp->tp != ZTM_KEY ||
-		    exp100ths < tmoutp->exp100ths) {
+		    exp100ths <= tmoutp->exp100ths) {
+                    // MY DEBUG
+                    FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                    fprintf( _F, "-- CALC_TIMEOUT() %d != %d || %d <= %d ZTM_FUNC(%d)\n", tmoutp->tp, ZTM_KEY, exp100ths, tmoutp->exp100ths, ZTM_FUNC );
+                    fclose(_F);
+
 		    tmoutp->exp100ths = exp100ths;
 		    tmoutp->tp = ZTM_FUNC;
 		}
 	    }
 	    break;
 	}
 	/* In case we called a function which messed up the display... */
 	if (resetneeded)
 	    zrefresh();
     }
@@ -508,20 +548,24 @@ raw_getbyte(long do_keytmout, char *cptr)
     struct ttyinfo ti;
 #endif
 #ifndef HAVE_POLL
 # ifdef HAVE_SELECT
     fd_set foofd, errfd;
     FD_ZERO(&errfd);
 # endif
 #endif
 
     calc_timeout(&tmout, do_keytmout);
+    // MY DEBUG
+    FILE *_F = fopen("/tmp/recursive.txt", "a+");
+    fprintf( _F, "-- INIT tmout.tp(%d) ZTM_NONE(%d) ZTM_KEY(%d) / BEGIN RAW_GETBYTE() zle_main.c\n", tmout.tp, ZTM_NONE, ZTM_KEY );
+    fclose(_F);
 
     /*
      * Handle timeouts and watched fd's.  If a watched fd or a function
      * timeout triggers we restart any key timeout.  This is likely to
      * be harmless: the combination is extremely rare and a function
      * is likely to occupy the user for a little while anyway.  We used
      * to make timeouts take precedence, but we can't now that the
      * timeouts may be external, so we may have both a permanent watched
      * fd and a long-term timeout.
      */
@@ -600,43 +644,78 @@ raw_getbyte(long do_keytmout, char *cptr)
 		    if (fd > fdmax)
 			fdmax = fd;
 		}
 	    }
 	    FD_ZERO(&errfd);
 
 	    if (tmout.tp != ZTM_NONE) {
 		expire_tv.tv_sec = tmout.exp100ths / 100;
 		expire_tv.tv_usec = (tmout.exp100ths % 100) * 10000L;
 		tvptr = &expire_tv;
+
+                // MY DEBUG
+                FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                fprintf( _F, "\n-- tmoutp != ZTM_NONE / raw_getbyte() zle_main.c\n" );
+                fclose(_F);
 	    }
-	    else
+	    else {
+                // MY DEBUG
+                FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                fprintf( _F, "\n-- FINAL (STOP) tmoutp == ZTM_NONE / raw_getbyte() zle_main.c\n" );
+                fclose(_F);
+
 		tvptr = NULL;
+            }
 
 	    winch_unblock();
 	    selret = select(fdmax+1, (SELECT_ARG_2_T) & foofd,
 			    NULL, NULL, tvptr);
 	    winch_block();
 # endif
 	    /*
 	     * Make sure a user interrupt gets passed on straight away.
 	     */
-	    if (selret < 0 && (errflag || retflag || breaks || exit_pending))
+	    if (selret < 0 && (errflag || retflag || breaks || exit_pending)) {
+                // MY DEBUG
+                FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                fprintf( _F, "-- Doing break [selret:%d] / zle_main.c: errflag: %d, retflag: %d, breaks: %d, exit_pending: %d\n",
+                            selret, errflag, retflag, breaks, exit_pending );
+                fclose(_F);
 		break;
+            } else {
+                // MY DEBUG
+                FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                fprintf( _F, "-- NOT doing break selret[%d] / zle_main.c: errflag: %d, retflag: %d, breaks: %d, exit_pending: %d\n",
+                            selret, errflag, retflag, breaks, exit_pending );
+                fclose(_F);
+            }
+
 	    /*
 	     * Try to avoid errors on our special fd's from
 	     * messing up reads from the terminal.  Try first
 	     * with all fds, then try unsetting the special ones.
 	     */
 	    if (selret < 0 && !errtry) {
+                // MY DEBUG
+                FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                fprintf( _F, "-- Trying again selret[%d], !errtry[%d] / zle_main.c\n", selret, errtry );
+                fclose(_F);
+
 		errtry = 1;
 		continue;
-	    }
+	    } else {
+                // MY DEBUG
+                FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                fprintf( _F, "--  Passed !errtry(errtry:%d) selret[%d] / zle_main.c\n", errtry, selret );
+                fclose(_F);
+            }
+
 	    if (selret == 0) {
 		/*
 		 * Nothing ready and no error, so we timed out.
 		 */
 		switch (tmout.tp) {
 		case ZTM_NONE:
 		    /* keeps compiler happy if not debugging */
 #ifdef DEBUG
 		    dputs("BUG: timeout fired with no timeout set.");
 #endif
@@ -669,20 +748,24 @@ raw_getbyte(long do_keytmout, char *cptr)
 		case ZTM_MAX:
 		    /*
 		     * Reached the limit of our range, but not the
 		     * actual timeout; recalculate the timeout.
 		     * We're cheating with the key timeout here:
 		     * if one clashed with a function timeout we
 		     * reconsider the key timeout from scratch.
 		     * The effect of this is microscopic.
 		     */
 		    calc_timeout(&tmout, do_keytmout);
+                    // MY DEBUG
+                    FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                    fprintf( _F, "^^^ LOOP-CALLED calc_timeout: tmout.tp == %d / zle_main.c\n", tmout.tp );
+                    fclose(_F);
 		    break;
 		}
 		/*
 		 * If we handled the timeout successfully,
 		 * carry on.
 		 */
 		if (selret == 0)
 		    continue;
 	    }
 	    /* If error or unhandled timeout, give up. */
@@ -888,22 +971,36 @@ getbyte(long do_keytmout, int *timeout)
 		   the counter (icnt) so that this happens 20 times and than
 		   the shell gives up (yes, this is a bit dirty...). */
 		if ((zlereadflags & ZLRF_IGNOREEOF) && icnt++ < 20)
 		    continue;
 		stopmsg = 1;
 		zexit(1, 0);
 	    }
 	    icnt = 0;
 	    if (errno == EINTR) {
 		die = 0;
+                static int counter = 0;
+
+                // MY DEBUG
+                FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                fprintf( _F, "-- Got EINTR %d\n", ++counter );
+                fclose(_F);
+
 		if (!errflag && !retflag && !breaks && !exit_pending)
+                {
+                    // MY DEBUG
+                    FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                    fprintf( _F, "-- Continuing despite EINTR / zle_main.c: errflag: %d, retflag: %d, breaks: %d, exit_pending: %d\n",
+                                errflag, retflag, breaks, exit_pending );
+                    fclose(_F);
 		    continue;
+                }
 		errflag &= ~ERRFLAG_ERROR;
 		breaks = obreaks;
 		errno = old_errno;
 		return lastchar = EOF;
 	    } else if (errno == EWOULDBLOCK) {
 		fcntl(0, F_SETFL, 0);
 	    } else if (errno == EIO && !die) {
 		ret = opts[MONITOR];
 		opts[MONITOR] = 1;
 		attachtty(mypgrp);
@@ -1115,20 +1212,24 @@ zlecore(void)
 		if (eofsent)
 		    break;
 	    }
 	    handleprefixes();
 	    /* for vi mode, make sure the cursor isn't somewhere illegal */
 	    if (invicmdmode() && zlecs > findbol() &&
 		(zlecs == zlell || zleline[zlecs] == ZWC('\n')))
 		DECCS();
 	    handleundo();
 	} else {
+            // MY DEBUG
+            FILE *_F = fopen("/tmp/recursive.txt", "a+");
+            fprintf( _F, "-- Setting error in zlecore.c\n" );
+            fclose(_F);
 	    errflag |= ERRFLAG_ERROR;
 	    break;
 	}
 
 	redrawhook();
 #ifdef HAVE_POLL
 	if (baud && !(lastcmd & ZLE_MENUCMP)) {
 	    struct pollfd pfd;
 	    int to = cost * costmult / 1000; /* milliseconds */
 
diff --git a/Src/signals.c b/Src/signals.c
index e2587dc..0bbda97 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -638,20 +638,25 @@ zhandler(int sig)
     case SIGINT:
         if (!handletrap(SIGINT)) {
 	    if ((isset(PRIVILEGED) || isset(RESTRICTED)) &&
 		isset(INTERACTIVE) && noerrexit < 0)
 		zexit(SIGINT, 1);
             if (list_pipe || chline || simple_pline) {
                 breaks = loops;
                 errflag |= ERRFLAG_INT;
 		inerrflush();
 		check_cursh_sig(SIGINT);
+
+                // MY DEBUG
+                FILE *_F = fopen("/tmp/recursive.txt", "a+");
+                fprintf( _F, "## set errflag to %d (ERRFLAG_INT:%d) / signals.c\n", errflag, ERRFLAG_INT );
+                fclose(_F);
             }
 	    lastval = 128 + SIGINT;
         }
         break;
 
 #ifdef SIGWINCH
     case SIGWINCH:
         adjustwinsize(1);  /* check window size and adjust */
 	(void) handletrap(SIGWINCH);
         break;


Messages sorted by: Reverse Date, Date, Thread, Author