English version
Accueil     À propos     Téléchargement     Ressources     Contactez-nous    

Ce site est rarement mis à jour. Pour les informations les plus récentes, rendez-vous sur le nouveau site OCaml à l'adresse ocaml.org.

Browse thread
[Caml-list] toplevel is hanging
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: 2001-04-23 (19:37)
From: Chris Hecker <checker@d...>
Subject: Re: [Caml-list] toplevel is hanging

>Did anybody have 
>similar experiences and is there any way around?

This sounds very similar to the problem I had running with the toplevel on emacs 20.7.1 and Win2k.  If so, it's not Tuareg's fault (I use caml-mode), it's emacs' fault.  I thought I posted about this, but I can't find it, so I guess not.  I spent an entire day debugging this, including building the compiler, the bytecode runtime, emacs, and debugging a ton of code interacting between the two processes.  Here goes:

What's happening is that the toplevel sends a string (either "# ", "  ", or "* " depending on if you're in a comment ("* " is only in 3.01), it's seen a ;;, etc.) after every line you send to it.  This is what keeps you indented when you do multiline stuff.  However, it also sends all those strings even if you're piping code directly do it (it can't tell whether you hit return at the prompt or sent it a \n in a region).

So, there's [what I'd call] a bug in the way process-send-region (which is aliased to comint-send-region, which is what's called to send stuff to consoles inside emacs) handles output.  If you have a lot of stuff and you want to send it to the toplevel, process-send-region will write to the process' handle, but not try to read.  Well, if it's enough stuff that the OS buffer fills up and emacs blocks on the write, then the other process has to grind through the data to eat it all up and unblock emacs.  Unfortunately, the caml toplevel is busy outputting the two-character strings (above) after every "\n" that it sees, and so if you send it a bunch of code, the write pipe back to emacs fills up, because emacs isn't reading from it.  So, you just deadlocked the two processes.

There are two fixes:

1.  Recompile the toplevel to not output "  " and "* " on newlines.  This is trivial (make sure you copy the new toplevel lib into your lib dir so ocamlmktop builds the new one).  This is what I did, and it fixed the problem (and I don't care about the auto-indent on return at the prompt).  The fix is to go to toplevel/toploop.ml, and the function refill_lexbuf near the bottom.  There'll be an output_string at the top of the function that outputs one of the strings.  Make the "  " a "" (and the "* " a "" if you're on 3.01).  It's a hack, to be sure, but it's simple and it works.

2.  Fix emacs.  The documentation for process-send-region says "If the region is more than 500 characters long, it is sent in several bunches.  This may happen even for shorter regions. Output from processes can arrive in between bunches."  They did this to fix this exact process interlock problem.  Of course, this is not what the source code does.  The source only breaks up _lines_ that are longer than a certain length, but the problem is the regions we're sending have short lines, but lots of newlines.  If the code actually did what the docs say then this wouldn't have happened.  I did not feel like messing with the heinous emacs source (this function is particularly beautiful :), so I did #1.

Hope this helps.

As a bonus, this will also fix the weird thing where the error message would be spaced way over in the inferior buffer (I don't know if you have that problem or not).  This was because all the spaces got output before the error message.


PS.  As another bonus, here's what I bind to ^C^T.  This evals the entire file, which makes it really easy to interactively develop a standalone program (obviously, since I was evaling entire files, I ran into the hang problem pretty early on, once the source got to ~500 lines):

(define-key caml-mode-map "\C-c\C-t"
               (lambda ()
                 "Eval the entire buffer with *inferior-caml*"
                 (inferior-caml-eval-region (point-min) (point-max))))

To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr