Parallel CAML

Daniel de Rauglaudre (ddr@peray)
Mon, 21 Dec 1992 17:25:40 +0900 (MET)

From: Daniel de Rauglaudre <ddr@peray>
Message-Id: <9212211625.AA23944@peray.inria.fr>
Subject: Parallel CAML
To: caml-list@margaux
Date: Mon, 21 Dec 1992 17:25:40 +0900 (MET)

I send here the files for my implementation of continuations in caml-light.
Without warranty: it's a prototype!

Daniel de Rauglaudre
ddr@margaux.inria.fr

#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 12/21/1992 16:19 UTC by ddr@margaux
# Source directory /home/margaux/formel1/ddr/scratch/tmp
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 353 -rw-r--r-- Makefile
# 697 -rw-rw-r-- README
# 6341 -rw-r--r-- callcc.c
# 299 -rw-r--r-- callcc.ml
# 601 -rw-r--r-- callcc.mli
# 70 -rwxr-xr-x camltop
# 1015 -rw-r--r-- concur.ml
# 109 -rw-rw-r-- example.ml
#
# ============= Makefile ==============
if test -f 'Makefile' -a X"$1" != X"-c"; then
echo 'x - skipping Makefile (File already exists)'
else
echo 'x - extracting Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
CAMLTOP=caml-light
CFLAGS=-I$(CAMLTOP)/src/runtime -UNDEBUG -O
CAMLMKTOP=camlmktop
X
all: camltop.out callcc.zo
X
camltop.out: callcc.zo callcc.o
X $(CAMLMKTOP) -custom callcc.zo callcc.o $(UNIX)
X
clean:
X rm -f *.o *.zi *.zo *.out *.bak *~
X
.mli.zi:
X camlc -c $(ZFLAGS) $<
X
.ml.zo:
X camlc -c $(ZFLAGS) $<
X
.SUFFIXES: .mli .zi .ml .zo
X
callcc.zo: callcc.zi
SHAR_EOF
chmod 0644 Makefile ||
echo 'restore of Makefile failed'
Wc_c="`wc -c < 'Makefile'`"
test 353 -eq "$Wc_c" ||
echo 'Makefile: original size 353, current size' "$Wc_c"
fi
# ============= README ==============
if test -f 'README' -a X"$1" != X"-c"; then
echo 'x - skipping README (File already exists)'
else
echo 'x - extracting README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'README' &&
To make a toplevel holding the continuations functions:
X
1- Edit the file "Makefile":
X
Set the variable CAMLTOP to the main directory of the distribution
of Caml-Light 0.5. This was necessary because some usefull include files are
not installed in the standard caml-light library (/usr/local/lib/caml-light).
X
2- Run "make"
X
This compiles callcc.c, callcc.ml, callcc.mli and creates the toplevel
camltop.out.
X
X
To execute this toplevel, just type: ./camltop
X
X
There is a small test in "example.ml".
See also the file "concur.ml" for a small implementation of coroutines
using channels.
X
X
This files are given without warranty. This is a prototype.
X
X Daniel de Rauglaudre
X ddr@margaux.inria.fr
SHAR_EOF
chmod 0664 README ||
echo 'restore of README failed'
Wc_c="`wc -c < 'README'`"
test 697 -eq "$Wc_c" ||
echo 'README: original size 697, current size' "$Wc_c"
fi
# ============= callcc.c ==============
if test -f 'callcc.c' -a X"$1" != X"-c"; then
echo 'x - skipping callcc.c (File already exists)'
else
echo 'x - extracting callcc.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'callcc.c' &&
/* $Id: callcc.c,v 1.11 92/12/21 11:59:52 ddr Exp $ */
X
#include <assert.h>
#ifndef NDEBUG
#include <stdio.h>
#define private
#define public
#else
#define private static
#define public
#endif
X
#define Setup_for_gc
#define Restore_after_gc
#include "mlvalues.h"
#include "stacks.h"
#include "prims.h"
#include "memory.h"
X
#define ret(sp) ((struct return_frame *) (sp))
#define rsp extern_rsp
#define asp extern_asp
X
private unsigned long min_as_size = 0, min_rs_size = 0;
private int trace_if_major = 1;
X
#undef CONTCNT
#ifdef CONTCNT
private int cont_cnt = 0;
#endif
X
#undef CONTSZ
#ifdef CONTSZ
private int cont_max_size = 0;
#endif
X
#undef TRACE
X
public value save_cont (v)
value v;
{
X int size_in_longs;
X register value *p, *q;
X value *r;
X value *arg_stack_start = arg_stack_high - min_as_size;
X value *ret_stack_start = ret_stack_high - min_rs_size;
X int arg_stack_len = arg_stack_start - asp;
X int ret_stack_len = ret_stack_start - rsp;
/* bogus mark any address not in the heap */
#define BOGUSMARK ((value) save_cont)
X
X assert (c_roots_head == NULL);;
X
X if (arg_stack_len < 0 || ret_stack_len < 0)
X failwith ("callcc: incorrect stack start");
X size_in_longs = 3 + arg_stack_len + ret_stack_len;
#ifdef CONTCNT
X size_in_longs++;
X printf ("callcc: save cont no %d\n", cont_cnt);
#endif
#if 0
X printf ("callcc: continuation size (in longs) = %d\n", size_in_longs);
#endif
#ifdef CONTSZ
X if (size_in_longs > cont_max_size) {
X cont_max_size = size_in_longs;
X printf ("callcc: max cont size so far = %d\n", cont_max_size);
X }
#endif
if (size_in_longs < Max_young_wosize) {
X value accu;
X Alloc_small (accu, size_in_longs, 0);
X r = (value *) accu;
X }
X else {
X if (trace_if_major)
X printf ("**** continuation allocated in MAJOR heap\n");
X Setup_for_gc;
X minor_collection ();
X r = (value *) alloc_shr (size_in_longs, 0);
X Restore_after_gc;
X }
X p = r;
X
#ifdef CONTCNT
X *p++ = Val_long (cont_cnt++);
#endif
X /* save sizes of arg & ret & tp stacks */
#ifdef TRACE
X printf ("callcc: arg stack size = %d\n", arg_stack_len);
X printf ("callcc: ret stack size = %d\n", ret_stack_len);
X printf ("callcc: relative tp = %d\n", ret_stack_start - (value *) tp);
#endif
X *p++ = Val_long (arg_stack_len);
X *p++ = Val_long (ret_stack_len);
X *p++ = Val_long (ret_stack_start - (value *) tp);
X
X /* save arg stack; mind the MARKs! */
X for (q = asp; q < arg_stack_start; p++, q++) {
X if (*q == MARK) *p = BOGUSMARK;
#ifndef NDEBUG
X else if (*q == BOGUSMARK) {
X printf ("*** quel est le fils de pute ?\n");
X exit (1);
X }
#endif
X else *p = *q;
X }
X
X /* save ret stack */
X for (q = rsp; q < ret_stack_start; ) {
X int i = ret(q)->cache_size;
X ret(p)->env = ret(q)->env;
X ret(p)->pc = (code_t) Val_long(ret(q)->pc);
X ret(p)->cache_size = Val_long(i);
X q += sizeof(struct return_frame)/sizeof(value);
X p += sizeof(struct return_frame)/sizeof(value);
X while (--i >= 0) *p++ = *q++;
X }
X assert (q == ret_stack_start);
X assert (p == r + 3 + arg_stack_len + ret_stack_len);
#ifdef TRACE
X printf ("callcc: terminated ok\n");
#endif
X
X return (value) r;
}
X
public value restore_cont (k, v)
value k, v;
{
X register value *p, *q;
X value *arg_stack_start = arg_stack_high - min_as_size;
X value *ret_stack_start = ret_stack_high - min_rs_size;
X int cache_size = ret(rsp)->cache_size;
X
X assert (c_roots_head == NULL);;
X
X p = (value *) k;
X
#ifdef CONTCNT
X printf ("throw: restore cont no %d\n", Long_val (*p++));
#endif
X
X /* restore positions of arg & ret & tp stacks */
X asp = arg_stack_start - Long_val (*p++);
X rsp = ret_stack_start - Long_val (*p++);
X tp = (struct trap_frame *) (ret_stack_start - Long_val (*p++));
#ifdef TRACE
X printf ("throw: arg stack size = %d\n", arg_stack_start - asp);
X printf ("throw: ret stack size = %d\n", ret_stack_start - rsp);
X printf ("throw: relative tp = %d\n", ret_stack_start - (value *) tp);
#endif
X
X /* restore arg stack */
X for (q = asp; q < arg_stack_start; p++, q++) {
X if (*p == BOGUSMARK) *q = MARK;
X else *q = *p;
X }
X
X /* restore ret stack */
X for (q = rsp; q < ret_stack_start; ) {
X int i = Long_val (ret(p)->cache_size);
X ret(q)->env = ret(p)->env;
X ret(q)->pc = (code_t) Long_val ((value) ret(p)->pc);
X ret(q)->cache_size = i;
X p += sizeof(struct return_frame)/sizeof(value);
X q += sizeof(struct return_frame)/sizeof(value);
X while (--i >= 0) *q++ = *p++;
X }
X assert (q == ret_stack_start);
X assert (p == (value *) k + 3 + (arg_stack_start - asp) + (ret_stack_start - rsp));
X
X if (cache_size != ret(rsp)->cache_size) {
X value env = ret(rsp)->env;
X rsp -= (cache_size - ret(rsp)->cache_size);
X ret(rsp)->env = env;
X }
#if 1
X if (*asp != MARK)
X printf ("hmm... asp != MARK\n");
#endif
X asp--; /* not actually a pop: just because C_CALL2 adds 1 to asp */
#ifdef TRACE
X printf ("throw: terminated ok\n");
#endif
X return v;
}
X
public value new_stack (v)
value v;
{
X /* 2 frames on ret stack given:
X - 1 for returning from C
X - 1 for possible throw of this stack (throw uses normal return)
X */
X int c_cache_size = ret(rsp)->cache_size;
X int c_len = sizeof(struct return_frame)/sizeof(value) + c_cache_size;
X int ml_cache_size = ret(rsp + c_len)->cache_size;
X int ml_len = sizeof(struct return_frame)/sizeof(value) + ml_cache_size;
X value len = c_len + ml_len;
X value *src = rsp + len;
X
#if 0
X printf ("new_stack: c_cache_size = %d\n", c_cache_size);
X printf ("new_stack: ml_cache_size = %d\n", ml_cache_size);
#endif
X asp = arg_stack_high;
X rsp = ret_stack_high;
X tp = (struct trap_frame *) ret_stack_high;
X while (--len >= 0) *--rsp = *--src;
#ifdef TRACE
X printf ("new_stack: terminated ok\n");
#endif
X return v;
}
X
public value get_stack_pos (v)
value v;
{
value ms;
Alloc_small (ms, 2, 0);
Field (ms, 0) = Val_long (arg_stack_high - asp);
Field (ms, 1) = Val_long (ret_stack_high - rsp
X - sizeof (struct return_frame) / sizeof (value)
X - ret(rsp)->cache_size);
X return ms;
}
X
public value get_min_cont (v)
value v;
{
value ms;
Alloc_small (ms, 2, 0);
Field (ms, 0) = Val_long (min_as_size);
Field (ms, 1) = Val_long (min_rs_size);
X return ms;
}
X
public value set_min_cont (ms)
value ms;
{
min_as_size = Long_val (Field (ms, 0));
min_rs_size = Long_val (Field (ms, 1));
return Atom (0);
}
X
public value set_trace_major (b)
value b;
{
X trace_if_major = (b != Atom(0));
X return Atom(0);
}
SHAR_EOF
chmod 0644 callcc.c ||
echo 'restore of callcc.c failed'
Wc_c="`wc -c < 'callcc.c'`"
test 6341 -eq "$Wc_c" ||
echo 'callcc.c: original size 6341, current size' "$Wc_c"
fi
# ============= callcc.ml ==============
if test -f 'callcc.ml' -a X"$1" != X"-c"; then
echo 'x - skipping callcc.ml (File already exists)'
else
echo 'x - extracting callcc.ml (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'callcc.ml' &&
(* $Id: callcc.ml,v 1.11 92/12/21 11:59:55 ddr Exp $ *)
X
let callcc f =
f (save_cont ())
;;
X
let throw =
restore_cont
;;
X
let handle_cont f a =
let mc = get_min_cont () in
set_min_cont (get_stack_pos ());
let x =
try f a with x -> set_min_cont mc; raise x
in
set_min_cont mc; x
;;
SHAR_EOF
chmod 0644 callcc.ml ||
echo 'restore of callcc.ml failed'
Wc_c="`wc -c < 'callcc.ml'`"
test 299 -eq "$Wc_c" ||
echo 'callcc.ml: original size 299, current size' "$Wc_c"
fi
# ============= callcc.mli ==============
if test -f 'callcc.mli' -a X"$1" != X"-c"; then
echo 'x - skipping callcc.mli (File already exists)'
else
echo 'x - extracting callcc.mli (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'callcc.mli' &&
(* $Id: callcc.mli,v 1.13 92/12/21 11:59:57 ddr Exp $ *)
X
type 'a cont;;
X
value callcc : ('a cont -> 'a) -> 'a;;
value throw : 'a cont -> 'a -> 'b;;
value handle_cont : ('a -> 'b) -> 'a -> 'b;;
value new_stack : unit -> unit = 1 "new_stack";;
X
value save_cont : unit -> 'a cont = 1 "save_cont";;
value restore_cont : 'a cont -> 'a -> 'b = 2 "restore_cont";;
value get_stack_pos : unit -> int * int = 1 "get_stack_pos";;
value get_min_cont : unit -> int * int = 1 "get_min_cont";;
value set_min_cont : int * int -> unit = 1 "set_min_cont";;
value set_trace_major : bool -> unit = 1 "set_trace_major";;
SHAR_EOF
chmod 0644 callcc.mli ||
echo 'restore of callcc.mli failed'
Wc_c="`wc -c < 'callcc.mli'`"
test 601 -eq "$Wc_c" ||
echo 'callcc.mli: original size 601, current size' "$Wc_c"
fi
# ============= camltop ==============
if test -f 'camltop' -a X"$1" != X"-c"; then
echo 'x - skipping camltop (File already exists)'
else
echo 'x - extracting camltop (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'camltop' &&
#!/bin/sh -e
X
exec ./camltop.out -stdlib /usr/local/lib/caml-light $*
SHAR_EOF
chmod 0755 camltop ||
echo 'restore of camltop failed'
Wc_c="`wc -c < 'camltop'`"
test 70 -eq "$Wc_c" ||
echo 'camltop: original size 70, current size' "$Wc_c"
fi
# ============= concur.ml ==============
if test -f 'concur.ml' -a X"$1" != X"-c"; then
echo 'x - skipping concur.ml (File already exists)'
else
echo 'x - extracting concur.ml (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'concur.ml' &&
(* $Id: concur.ml,v 1.9 92/09/07 14:51:05 ddr Exp $ *)
X
#open "callcc";;
X
type 'a option = None | Some of 'a;;
let queue_get q =
try Some (queue__take q) with queue__Empty -> None
;;
X
type 'a chan = {
inq : 'a cont queue__t;
outq : ('a * unit cont) queue__t
};;
X
let rdyQ = (queue__new () : unit cont queue__t);;
let channel () = {inq = queue__new (); outq = queue__new ()};;
X
let spawn f =
callcc (fun parent_k ->
queue__add parent_k rdyQ;
f ();
throw (queue__take rdyQ) ()
)
;;
X
let send ch msg =
callcc (fun send_k ->
match queue_get ch.inq with
Some accept_k ->
queue__add send_k rdyQ;
throw accept_k msg
| None ->
queue__add (msg, send_k) ch.outq;
throw (queue__take rdyQ) ()
)
;;
X
let accept ch =
callcc (fun accept_k ->
match queue_get ch.outq with
Some (msg, send_k) ->
queue__add send_k rdyQ;
throw accept_k msg
| None ->
queue__add accept_k ch.inq;
throw (queue__take rdyQ) ()
)
;;
SHAR_EOF
chmod 0644 concur.ml ||
echo 'restore of concur.ml failed'
Wc_c="`wc -c < 'concur.ml'`"
test 1015 -eq "$Wc_c" ||
echo 'concur.ml: original size 1015, current size' "$Wc_c"
fi
# ============= example.ml ==============
if test -f 'example.ml' -a X"$1" != X"-c"; then
echo 'x - skipping example.ml (File already exists)'
else
echo 'x - extracting example.ml (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'example.ml' &&
#open "callcc";;
let test a = callcc (fun k -> 3 + (if a then 1 else throw k 10));;
test true;;
test false;;
SHAR_EOF
chmod 0664 example.ml ||
echo 'restore of example.ml failed'
Wc_c="`wc -c < 'example.ml'`"
test 109 -eq "$Wc_c" ||
echo 'example.ml: original size 109, current size' "$Wc_c"
fi
exit 0