Let's go into detail. Ocam debugger consists of the the two parts: the
client (byterun/debugger.c linked into debuggee) and the server
(ocamldebug). The following issues should be addressed to make a Windows
port:
1. Checkpointing is done via Unix fork() (client)
The most problematic one. I have spend a fair amount of time trying to find
an acceptable solution.
a) direct port of fork() to Windows. There is a BSD-licenced Windows fork()
in tcsh sources [2] that could be used. It's based on Cygwin ideas. But how
to handle dynamically loaded DLLs (loaded via LoadLibrary())? I asked the
author (Amol Deshpande) and he replied:
"DLLs that are dynamically loaded are a can of worms. I would not support
those if I were you."
BTW, does Cygwin do this right? I doubt at least.
b) some checkpoint library. Although Web search gives many references, e.g.
[3], I have not found yet anything ready-to-use, even commercial!
2. Unix select (server)
It is a problem because server waits for network and console events
simultaneously. To work on Windows the main loop should probably be
multi-threaded.
3. Unix sockets (client & server)
Probably can be ignored. Internet sockets are quite enough.
So what is done now.
- Client
It's ported without (1) and (3). To me it's quite usable even without
checkpoints.
- Server
I don't bother to do (2) right now (until the whole idea is accepted).
Currently I use cygwin-compiled ocamldebug with checkpoints and Unix sockets
disabled by default. It works well with the native Win32 clients.
- OcaIDE
Yes, with minor changes in OcaIDE the debugged works there.
If it's interesting for anyone I can publish a patch against Ocaml 3.10.1
- Dmitry Bely
[1]
http://caml.inria.fr/pub/ml-archives/caml-list/1999/03/f44178e212e78826bcbdee52ddf6fd91.en.html
http://caml.inria.fr/pub/ml-archives/caml-list/2002/10/ed776d7376ed7a9676d4a9981372ccdf.fr.html
Yes, that's definitely interesting for us!
Is there any hope to build the server with the mingw or msvc port?
-- Alain
_______________________________________________
Caml-list mailing list. Subscription management:
http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
Archives: http://caml.inria.fr
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs
As soon as the following function is rewritten:
debugger/input_handling.ml
(* Handle active files until `continue_main_loop' is false. *)
let main_loop () =
let old_state = !continue_main_loop in
try
continue_main_loop := true;
while !continue_main_loop do
try
let (input, _, _) =
select (List.map fst !active_files) [] [] (-1.)
in
List.iter
(function fd ->
let (funct, iochan) = (List.assoc fd !active_files) in
funct iochan)
input
with
Unix_error (EINTR, _, _) -> ()
done;
continue_main_loop := old_state
with
x ->
continue_main_loop := old_state;
raise x
here Unix.select() waits for both network and user input events. We
could split this into 2 threads, but how to interrupt network select()
when we going to exit? Well, we could use some small timeout value for
select() (say 500ms) and restart it the loop when !continue_main_loop
is set, but this looks not very elegant... Or it's OK?
The point is not to modify win32unix library or write Win32-specific C
functions for ocamldebug. I believe it's necessary to be ever accepted
by INRIA.
- Dmitry Bely
http://raevnos.pennmush.org/code/ethread/doc/MsgQueue.html
Cheers,
Bene
2008/2/5, Dmitry Bely <dmitr...@gmail.com>:
--
Calvin: I try to make everyone's day a little more
surreal.
(From Calvin & Hobbes)
Do you know how Cygwin emulate the desired behavior? Does it use threads?
-- Alain
It surely use WaitForMultipleObjects() instead of select(). The
implementation is quite complicated; GDB's one seems to be better
showing an idea (see below).
But frankly speaking I don't like to add any C code here - in fact it
means altering win32unix library that is unlikely to happen. Can it be
solved on Caml level? Anyone? Is select() with small timeout is
acceptable?
/* Wrapper for select. On Windows systems, where the select interface
only works for sockets, this uses the GDB serial abstraction to
handle sockets, consoles, pipes, and serial ports.
The arguments to this function are the same as the traditional
arguments to select on POSIX platforms. */
int
gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout)
{
static HANDLE never_handle;
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
HANDLE h;
DWORD event;
DWORD num_handles;
int fd;
int num_ready;
int indx;
num_ready = 0;
num_handles = 0;
for (fd = 0; fd < n; ++fd)
{
HANDLE read = NULL, except = NULL;
struct serial *scb;
/* There is no support yet for WRITEFDS. At present, this isn't
used by GDB -- but we do not want to silently ignore WRITEFDS
if something starts using it. */
gdb_assert (!writefds || !FD_ISSET (fd, writefds));
if ((!readfds || !FD_ISSET (fd, readfds))
&& (!exceptfds || !FD_ISSET (fd, exceptfds)))
continue;
h = (HANDLE) _get_osfhandle (fd);
scb = serial_for_fd (fd);
if (scb)
serial_wait_handle (scb, &read, &except);
if (read == NULL)
read = h;
if (except == NULL)
{
if (!never_handle)
never_handle = CreateEvent (0, FALSE, FALSE, 0);
except = never_handle;
}
if (readfds && FD_ISSET (fd, readfds))
{
gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
handles[num_handles++] = read;
}
if (exceptfds && FD_ISSET (fd, exceptfds))
{
gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
handles[num_handles++] = except;
}
}
/* If we don't need to wait for any handles, we are done. */
if (!num_handles)
{
if (timeout)
Sleep (timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
return 0;
}
event = WaitForMultipleObjects (num_handles,
handles,
FALSE,
timeout
? (timeout->tv_sec * 1000
+ timeout->tv_usec / 1000)
: INFINITE);
/* EVENT can only be a value in the WAIT_ABANDONED_0 range if the
HANDLES included an abandoned mutex. Since GDB doesn't use
mutexes, that should never occur. */
gdb_assert (!(WAIT_ABANDONED_0 <= event
&& event < WAIT_ABANDONED_0 + num_handles));
if (event == WAIT_FAILED)
return -1;
if (event == WAIT_TIMEOUT)
return 0;
/* Run through the READFDS, clearing bits corresponding to descriptors
for which input is unavailable. */
h = handles[event - WAIT_OBJECT_0];
for (fd = 0, indx = 0; fd < n; ++fd)
{
HANDLE fd_h;
struct serial *scb;
if ((!readfds || !FD_ISSET (fd, readfds))
&& (!exceptfds || !FD_ISSET (fd, exceptfds)))
continue;
if (readfds && FD_ISSET (fd, readfds))
{
fd_h = handles[indx++];
/* This handle might be ready, even though it wasn't the handle
returned by WaitForMultipleObjects. */
if (fd_h != h && WaitForSingleObject (fd_h, 0) != WAIT_OBJECT_0)
FD_CLR (fd, readfds);
else
num_ready++;
}
if (exceptfds && FD_ISSET (fd, exceptfds))
{
fd_h = handles[indx++];
/* This handle might be ready, even though it wasn't the handle
returned by WaitForMultipleObjects. */
if (fd_h != h && WaitForSingleObject (fd_h, 0) != WAIT_OBJECT_0)
FD_CLR (fd, exceptfds);
else
num_ready++;
}
/* We created at least one event handle for this fd. Let the
device know we are finished with it. */
scb = serial_for_fd (fd);
if (scb)
serial_done_wait_handle (scb);
}
return num_ready;
}
- Dmitry Bely
I'm delighted to see your attempts at getting ocamldebug to work under
Windows.
Generally speaking, the Windows port is the part of OCaml where we
most desperately need outside help, as (1) it consumes quite a bit of
my very limited time, (2) it's a cost center for the Caml development
team (none of us uses Windows for our research activities), and (3)
none of us is competent with Win32 programming.
(For example, if anyone could help debugging PR#4399, that would be
much appreciated.)
Coming back to ocamldebug:
> The point is not to modify win32unix library or write Win32-specific C
> functions for ocamldebug. I believe it's necessary to be ever accepted
> by INRIA.
Actually, I would be happy with a Win32 implementation of Unix.select
that works over any combination of sockets and file descriptors.
Unfortunately, it looks like we'd need a gross hack involving threads,
WaitForMultipleObjects() and select(), but if someone comes up with an
implementation that isn't too gross, I'll be interested.
- Xavier Leroy
Alas, I have not migrated to Vista yet. But once the reporter has
Visual C++ experience I would recommend him to build OCaml from
sources with debug info enabled (if won't compile out-of-the-box but
the fix is trivial) and launch ocamlwin under debugger. When it should
become obvious where the access violation occurs.
> Coming back to ocamldebug:
>
> > The point is not to modify win32unix library or write Win32-specific C
> > functions for ocamldebug. I believe it's necessary to be ever accepted
> > by INRIA.
>
> Actually, I would be happy with a Win32 implementation of Unix.select
> that works over any combination of sockets and file descriptors.
> Unfortunately, it looks like we'd need a gross hack involving threads,
> WaitForMultipleObjects() and select(), but if someone comes up with an
> implementation that isn't too gross, I'll be interested.
Indeed, porting select() to Windows would be preferable.
WaitForMultipleObjects() can wait for console, pipe and network events
simultaneously so this should not be that hard (and multiple threads
are probably not necessary). Of course, there are some pitfalls like
this (taken from Cygwin sources):
/* Some types of object (e.g., consoles) wake up on "inappropriate" events
like mouse movements. The verify function will detect these
situations.
If it returns false, then this wakeup was a false alarm and
we should go
back to waiting. */
But at least I'll try.
- Dmitry Bely
There's a windows API function for that. As long as the newtork access can be
wrapped in the usual aysnchronous I/O primitives, there's a wait function
that will wait on an async conditition *or* a message.
Cheers, Kuba