revised Mac OS X sleeping; optional atomic mode for FFI callbacks

svn: r13016
This commit is contained in:
Matthew Flatt 2009-01-06 13:07:45 +00:00
parent f5c77109fa
commit 61685c72f9
19 changed files with 213 additions and 111 deletions

View File

@ -468,17 +468,20 @@
;; optionally applying a wrapper function to modify the result primitive ;; optionally applying a wrapper function to modify the result primitive
;; (callouts) or the input procedure (callbacks). ;; (callouts) or the input procedure (callbacks).
(define* (_cprocedure itypes otype (define* (_cprocedure itypes otype
#:abi [abi #f] #:wrapper [wrapper #f] #:keep [keep #f]) #:abi [abi #f]
(_cprocedure* itypes otype abi wrapper keep)) #:wrapper [wrapper #f]
#:keep [keep #f]
#:atomic? [atomic? #f])
(_cprocedure* itypes otype abi wrapper keep atomic?))
;; for internal use ;; for internal use
(define held-callbacks (make-weak-hasheq)) (define held-callbacks (make-weak-hasheq))
(define (_cprocedure* itypes otype abi wrapper keep) (define (_cprocedure* itypes otype abi wrapper keep atomic?)
(define-syntax-rule (make-it wrap) (define-syntax-rule (make-it wrap)
(make-ctype _fpointer (make-ctype _fpointer
(lambda (x) (lambda (x)
(and x (and x
(let ([cb (ffi-callback (wrap x) itypes otype abi)]) (let ([cb (ffi-callback (wrap x) itypes otype abi atomic?)])
(cond [(eq? keep #t) (hash-set! held-callbacks x cb)] (cond [(eq? keep #t) (hash-set! held-callbacks x cb)]
[(box? keep) [(box? keep)
(let ([x (unbox keep)]) (let ([x (unbox keep)])
@ -514,6 +517,7 @@
(define xs #f) (define xs #f)
(define abi #f) (define abi #f)
(define keep #f) (define keep #f)
(define atomic? #f)
(define inputs #f) (define inputs #f)
(define output #f) (define output #f)
(define bind '()) (define bind '())
@ -578,9 +582,10 @@
(begin (set! var (cadr xs)) (set! xs (cddr xs)) (loop)))] (begin (set! var (cadr xs)) (set! xs (cddr xs)) (loop)))]
... ...
[else (err "unknown keyword" (car xs))])) [else (err "unknown keyword" (car xs))]))
(when (keyword? k) (kwds [#:abi abi] [#:keep keep])))) (when (keyword? k) (kwds [#:abi abi] [#:keep keep] [#:atomic? atomic?]))))
(unless abi (set! abi #'#f)) (unless abi (set! abi #'#f))
(unless keep (set! keep #'#t)) (unless keep (set! keep #'#t))
(unless atomic? (set! atomic? #'#f))
;; parse known punctuation ;; parse known punctuation
(set! xs (map (lambda (x) (set! xs (map (lambda (x)
(syntax-case* x (-> ::) id=? [:: '::] [-> '->] [_ x])) (syntax-case* x (-> ::) id=? [:: '::] [-> '->] [_ x]))
@ -671,9 +676,9 @@
(string->symbol (string-append "ffi-wrapper:" n))) (string->symbol (string-append "ffi-wrapper:" n)))
body))]) body))])
#`(_cprocedure* (list #,@(filter-map car inputs)) #,(car output) #`(_cprocedure* (list #,@(filter-map car inputs)) #,(car output)
#,abi (lambda (ffi) #,body) #,keep)) #,abi (lambda (ffi) #,body) #,keep #,atomic?))
#`(_cprocedure* (list #,@(filter-map car inputs)) #,(car output) #`(_cprocedure* (list #,@(filter-map car inputs)) #,(car output)
#,abi #f #,keep))) #,abi #f #,keep #,atomic?)))
(syntax-case stx () (syntax-case stx ()
[(_ x ...) (begin (set! xs (syntax->list #'(x ...))) (do-fun))])) [(_ x ...) (begin (set! xs (syntax->list #'(x ...))) (do-fun))]))

View File

@ -297,6 +297,7 @@ and normally @scheme[_cprocedure] should be used instead of
@defproc[(_cprocedure [input-types (list ctype?)] @defproc[(_cprocedure [input-types (list ctype?)]
[output-type ctype?] [output-type ctype?]
[#:abi abi (or/c symbol/c #f) #f] [#:abi abi (or/c symbol/c #f) #f]
[#:atomic? atomic? any/c #f]
[#:wrapper wrapper (or/c #f (procedure? . -> . procedure?)) [#:wrapper wrapper (or/c #f (procedure? . -> . procedure?))
#f] #f]
[#:keep keep (or/c boolean? box? (any/c . -> . any/c)) [#:keep keep (or/c boolean? box? (any/c . -> . any/c))
@ -328,6 +329,16 @@ platform-dependent default; other possible values are
``cdecl''). This is especially important on Windows, where most ``cdecl''). This is especially important on Windows, where most
system functions are @scheme['stdcall], which is not the default. system functions are @scheme['stdcall], which is not the default.
If @scheme[atomic?] is true, then when a Scheme procedure is given
this procedure type and called from foreign code, then the PLT Scheme
virtual machine is put into atomic mode while evaluating the Scheme
procedure body. In atomic mode, other Scheme threads cannot run, so
the Scheme code must not call any function that potentially
synchronizes with other threads (including I/O functions). In
addition, the Scheme code must not raise an uncaught exception, it
must not perform any escaping continuation jumps, and its non-tail
recursion must be minimal to avoid C-level stack overflow.
The optional @scheme[wrapper], if provided, is expected to be a The optional @scheme[wrapper], if provided, is expected to be a
function that can change a callout procedure: when a callout is function that can change a callout procedure: when a callout is
generated, the wrapper is applied on the newly created primitive generated, the wrapper is applied on the newly created primitive
@ -394,7 +405,8 @@ values: @itemize[
(_fun fun-option ... maybe-args type-spec ... -> type-spec (_fun fun-option ... maybe-args type-spec ... -> type-spec
maybe-wrapper) maybe-wrapper)
([fun-option (code:line #:abi abi-expr) ([fun-option (code:line #:abi abi-expr)
(code:line #:keep keep-expr)] (code:line #:keep keep-expr)
(code:line #:atomic? atomic?-expr)]
[maybe-args code:blank [maybe-args code:blank
(code:line (id ...) ::) (code:line (id ...) ::)
(code:line id ::) (code:line id ::)

View File

@ -62,7 +62,8 @@ especially important on Windows, where most system functions are
@defproc[(ffi-callback [proc any/c] [in-types any/c] [out-type any/c] @defproc[(ffi-callback [proc any/c] [in-types any/c] [out-type any/c]
[abi (or/c symbol/c #f) #f]) [abi (or/c symbol/c #f) #f]
[atomic? any/c #f])
ffi-callback?]{ ffi-callback?]{
The symmetric counterpart of @scheme[ffi-call]. It receives a Scheme The symmetric counterpart of @scheme[ffi-call]. It receives a Scheme

View File

@ -1108,6 +1108,7 @@ typedef struct ffi_callback_struct {
Scheme_Object* proc; Scheme_Object* proc;
Scheme_Object* itypes; Scheme_Object* itypes;
Scheme_Object* otype; Scheme_Object* otype;
int call_in_scheduler;
} ffi_callback_struct; } ffi_callback_struct;
#define SCHEME_FFICALLBACKP(x) (SCHEME_TYPE(x)==ffi_callback_tag) #define SCHEME_FFICALLBACKP(x) (SCHEME_TYPE(x)==ffi_callback_tag)
#undef MYNAME #undef MYNAME
@ -2580,12 +2581,16 @@ void ffi_do_callback(ffi_cif* cif, void* resultp, void** args, void *userdata)
argv = argv_stack; argv = argv_stack;
else else
argv = scheme_malloc(argc * sizeof(Scheme_Object*)); argv = scheme_malloc(argc * sizeof(Scheme_Object*));
if (data->call_in_scheduler)
scheme_start_in_scheduler();
for (i=0, p=data->itypes; i<argc; i++, p=SCHEME_CDR(p)) { for (i=0, p=data->itypes; i<argc; i++, p=SCHEME_CDR(p)) {
v = C2SCHEME(SCHEME_CAR(p), args[i], 0, 0); v = C2SCHEME(SCHEME_CAR(p), args[i], 0, 0);
argv[i] = v; argv[i] = v;
} }
p = _scheme_apply(data->proc, argc, argv); p = _scheme_apply(data->proc, argc, argv);
SCHEME2C(data->otype, resultp, 0, p, NULL, NULL, 1); SCHEME2C(data->otype, resultp, 0, p, NULL, NULL, 1);
if (data->call_in_scheduler)
scheme_end_in_scheduler();
} }
/* see ffi-callback below */ /* see ffi-callback below */
@ -2688,6 +2693,7 @@ static Scheme_Object *foreign_ffi_callback(int argc, Scheme_Object *argv[])
data->proc = (argv[0]); data->proc = (argv[0]);
data->itypes = (argv[1]); data->itypes = (argv[1]);
data->otype = (argv[2]); data->otype = (argv[2]);
data->call_in_scheduler = (((argc > 4) && SCHEME_TRUEP(argv[4])));
#ifdef MZ_PRECISE_GC #ifdef MZ_PRECISE_GC
{ {
/* put data in immobile, weak box */ /* put data in immobile, weak box */
@ -2853,7 +2859,7 @@ void scheme_init_foreign(Scheme_Env *env)
scheme_add_global("ffi-call", scheme_add_global("ffi-call",
scheme_make_prim_w_arity(foreign_ffi_call, "ffi-call", 3, 4), menv); scheme_make_prim_w_arity(foreign_ffi_call, "ffi-call", 3, 4), menv);
scheme_add_global("ffi-callback", scheme_add_global("ffi-callback",
scheme_make_prim_w_arity(foreign_ffi_callback, "ffi-callback", 3, 4), menv); scheme_make_prim_w_arity(foreign_ffi_callback, "ffi-callback", 3, 5), menv);
s = scheme_intern_symbol("void"); s = scheme_intern_symbol("void");
t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct)); t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
t->so.type = ctype_tag; t->so.type = ctype_tag;

View File

@ -944,7 +944,8 @@ ffi_abi sym_to_abi(char *who, Scheme_Object *sym)
(callback "void*") (callback "void*")
(proc "Scheme_Object*") (proc "Scheme_Object*")
(itypes "Scheme_Object*") (itypes "Scheme_Object*")
(otype "Scheme_Object*")):} (otype "Scheme_Object*")
(call_in_scheduler "int")):}
/*****************************************************************************/ /*****************************************************************************/
/* Pointer objects */ /* Pointer objects */
@ -1969,12 +1970,16 @@ void ffi_do_callback(ffi_cif* cif, void* resultp, void** args, void *userdata)
argv = argv_stack; argv = argv_stack;
else else
argv = scheme_malloc(argc * sizeof(Scheme_Object*)); argv = scheme_malloc(argc * sizeof(Scheme_Object*));
if (data->call_in_scheduler)
scheme_start_in_scheduler();
for (i=0, p=data->itypes; i<argc; i++, p=SCHEME_CDR(p)) { for (i=0, p=data->itypes; i<argc; i++, p=SCHEME_CDR(p)) {
v = C2SCHEME(SCHEME_CAR(p), args[i], 0, 0); v = C2SCHEME(SCHEME_CAR(p), args[i], 0, 0);
argv[i] = v; argv[i] = v;
} }
p = _scheme_apply(data->proc, argc, argv); p = _scheme_apply(data->proc, argc, argv);
SCHEME2C(data->otype, resultp, 0, p, NULL, NULL, 1); SCHEME2C(data->otype, resultp, 0, p, NULL, NULL, 1);
if (data->call_in_scheduler)
scheme_end_in_scheduler();
} }
/* see ffi-callback below */ /* see ffi-callback below */
@ -2005,7 +2010,7 @@ void free_cl_cif_args(void *ignored, void *p)
/* (ffi-callback scheme-proc in-types out-type [abi]) -> ffi-callback */ /* (ffi-callback scheme-proc in-types out-type [abi]) -> ffi-callback */
/* the treatment of in-types and out-types is similar to that in ffi-call */ /* the treatment of in-types and out-types is similar to that in ffi-call */
/* the real work is done by ffi_do_callback above */ /* the real work is done by ffi_do_callback above */
{:(cdefine ffi-callback 3 4):} {:(cdefine ffi-callback 3 5):}
{ {
ffi_callback_struct *data; ffi_callback_struct *data;
Scheme_Object *itypes = argv[1]; Scheme_Object *itypes = argv[1];
@ -2070,7 +2075,8 @@ void free_cl_cif_args(void *ignored, void *p)
if (ffi_prep_cif(cif, abi, nargs, rtype, atypes) != FFI_OK) if (ffi_prep_cif(cif, abi, nargs, rtype, atypes) != FFI_OK)
scheme_signal_error("internal error: ffi_prep_cif did not return FFI_OK"); scheme_signal_error("internal error: ffi_prep_cif did not return FFI_OK");
{:(cmake-object "data" ffi-callback {:(cmake-object "data" ffi-callback
"cl_cif_args" "argv[0]" "argv[1]" "argv[2]"):} "cl_cif_args" "argv[0]" "argv[1]" "argv[2]"
"((argc > 4) && SCHEME_TRUEP(argv[4]))"):}
#ifdef MZ_PRECISE_GC #ifdef MZ_PRECISE_GC
{ {
/* put data in immobile, weak box */ /* put data in immobile, weak box */

View File

@ -1179,103 +1179,20 @@ int MrEdCheckForBreak(void)
/***************************************************************************/ /***************************************************************************/
#include <pthread.h> #include <pthread.h>
static volatile int thread_running;
static volatile int need_post; /* 0=>1 transition has a benign race condition, an optimization */
static SLEEP_PROC_PTR mzsleep;
static pthread_t watcher;
static volatile float sleep_secs;
/* These file descriptors act as semaphores: */ /* These file descriptors are used for breaking the event loop. */
static int watch_read_fd, watch_write_fd;
static int watch_done_read_fd, watch_done_write_fd;
/* These file descriptors are used for breaking the event loop.
See ARGH below. */
static int cb_socket_ready; static int cb_socket_ready;
static int ready_sock, write_ready_sock; static int ready_sock, write_ready_sock;
#ifdef MZ_PRECISE_GC
START_XFORM_SKIP;
#endif
static void *do_watch(void *fds)
{
while (1) {
char buf[1];
read(watch_read_fd, buf, 1);
mzsleep(sleep_secs, fds);
if (need_post) {
need_post = 0;
if (cb_socket_ready) {
/* Sometimes WakeUpProcess() doesn't work.
Try a notification socket as a backup.
See ARGH below. */
write(write_ready_sock, "y", 1);
}
}
write(watch_done_write_fd, "y", 1);
}
return NULL;
}
#ifdef MZ_PRECISE_GC
END_XFORM_SKIP;
#endif
static int StartFDWatcher(void (*mzs)(float secs, void *fds), float secs, void *fds) static int StartFDWatcher(void (*mzs)(float secs, void *fds), float secs, void *fds)
{ {
if (!watch_write_fd) { scheme_start_sleeper_thread(mzs, secs, fds, write_ready_sock);
int fds[2];
if (!pipe(fds)) {
watch_read_fd = fds[0];
watch_write_fd = fds[1];
} else {
return 0;
}
}
if (!watch_done_write_fd) {
int fds[2];
if (!pipe(fds)) {
watch_done_read_fd = fds[0];
watch_done_write_fd = fds[1];
} else {
return 0;
}
}
if (!watcher) {
if (pthread_create(&watcher, NULL, do_watch, fds)) {
return 0;
}
}
mzsleep = mzs;
sleep_secs = secs;
thread_running = 1;
need_post = 1;
write(watch_write_fd, "x", 1);
return 1; return 1;
} }
static void EndFDWatcher(void) static void EndFDWatcher(void)
{ {
char buf[1]; scheme_end_sleeper_thread();
if (thread_running) {
if (need_post) {
need_post = 0;
scheme_signal_received();
}
read(watch_done_read_fd, buf, 1);
thread_running = 0;
}
} }
void socket_callback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) void socket_callback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
@ -1369,11 +1286,8 @@ void MrEdMacSleep(float secs, void *fds, SLEEP_PROC_PTR mzsleep)
going++; going++;
if (need_post) /* useless check in principle, but an optimization if (WNE(&e, secs ? secs : kEventDurationForever))
in the case that the select() succeeds before QueueTransferredEvent(&e);
we even start */
if (WNE(&e, secs ? secs : kEventDurationForever))
QueueTransferredEvent(&e);
--going; --going;

View File

@ -23,6 +23,8 @@ scheme_get_current_thread
scheme_start_atomic scheme_start_atomic
scheme_end_atomic scheme_end_atomic
scheme_end_atomic_no_swap scheme_end_atomic_no_swap
scheme_start_in_scheduler
scheme_end_in_scheduler
scheme_out_of_fuel scheme_out_of_fuel
scheme_thread scheme_thread
scheme_thread_w_details scheme_thread_w_details
@ -43,6 +45,8 @@ scheme_wait_input_allowed
scheme_unless_ready scheme_unless_ready
scheme_in_main_thread scheme_in_main_thread
scheme_cancel_sleep scheme_cancel_sleep
scheme_start_sleeper_thread
scheme_end_sleeper_thread
scheme_make_thread_cell scheme_make_thread_cell
scheme_thread_cell_get scheme_thread_cell_get
scheme_thread_cell_set scheme_thread_cell_set

View File

@ -23,6 +23,8 @@ scheme_get_current_thread
scheme_start_atomic scheme_start_atomic
scheme_end_atomic scheme_end_atomic
scheme_end_atomic_no_swap scheme_end_atomic_no_swap
scheme_start_in_scheduler
scheme_end_in_scheduler
scheme_out_of_fuel scheme_out_of_fuel
scheme_thread scheme_thread
scheme_thread_w_details scheme_thread_w_details
@ -43,6 +45,8 @@ scheme_wait_input_allowed
scheme_unless_ready scheme_unless_ready
scheme_in_main_thread scheme_in_main_thread
scheme_cancel_sleep scheme_cancel_sleep
scheme_start_sleeper_thread
scheme_end_sleeper_thread
scheme_make_thread_cell scheme_make_thread_cell
scheme_thread_cell_get scheme_thread_cell_get
scheme_thread_cell_set scheme_thread_cell_set

View File

@ -25,6 +25,8 @@ EXPORTS
scheme_start_atomic scheme_start_atomic
scheme_end_atomic scheme_end_atomic
scheme_end_atomic_no_swap scheme_end_atomic_no_swap
scheme_start_in_scheduler
scheme_end_in_scheduler
scheme_out_of_fuel scheme_out_of_fuel
scheme_thread scheme_thread
scheme_thread_w_details scheme_thread_w_details
@ -45,6 +47,8 @@ EXPORTS
scheme_unless_ready scheme_unless_ready
scheme_in_main_thread scheme_in_main_thread
scheme_cancel_sleep scheme_cancel_sleep
scheme_start_sleeper_thread
scheme_end_sleeper_thread
scheme_make_thread_cell scheme_make_thread_cell
scheme_thread_cell_get scheme_thread_cell_get
scheme_thread_cell_set scheme_thread_cell_set

View File

@ -25,6 +25,8 @@ EXPORTS
scheme_start_atomic scheme_start_atomic
scheme_end_atomic scheme_end_atomic
scheme_end_atomic_no_swap scheme_end_atomic_no_swap
scheme_start_in_scheduler
scheme_end_in_scheduler
scheme_out_of_fuel scheme_out_of_fuel
scheme_thread scheme_thread
scheme_thread_w_details scheme_thread_w_details
@ -45,6 +47,8 @@ EXPORTS
scheme_unless_ready scheme_unless_ready
scheme_in_main_thread scheme_in_main_thread
scheme_cancel_sleep scheme_cancel_sleep
scheme_start_sleeper_thread
scheme_end_sleeper_thread
scheme_make_thread_cell scheme_make_thread_cell
scheme_thread_cell_get scheme_thread_cell_get
scheme_thread_cell_set scheme_thread_cell_set

View File

@ -9,10 +9,11 @@
unsigned long _stk_pos; unsigned long _stk_pos;
_stk_pos = (unsigned long)&_stk_pos; _stk_pos = (unsigned long)&_stk_pos;
if (STK_COMP(_stk_pos, (unsigned long)SCHEME_CURRENT_PROCESS->stack_end)) if (STK_COMP(_stk_pos, (unsigned long)SCHEME_CURRENT_PROCESS->stack_end)
&& !scheme_no_stack_overflow)
#else #else
# ifdef USE_STACKAVAIL # ifdef USE_STACKAVAIL
if (stackavail() < STACK_SAFETY_MARGIN) if ((stackavail() < STACK_SAFETY_MARGIN) && !scheme_no_stack_overflow)
# endif # endif
# if defined(UNIX_FIND_STACK_BOUNDS) || defined(WINDOWS_FIND_STACK_BOUNDS) \ # if defined(UNIX_FIND_STACK_BOUNDS) || defined(WINDOWS_FIND_STACK_BOUNDS) \
|| defined(MACOS_FIND_STACK_BOUNDS) || defined(ASSUME_FIXED_STACK_SIZE) \ || defined(MACOS_FIND_STACK_BOUNDS) || defined(ASSUME_FIXED_STACK_SIZE) \
@ -22,7 +23,8 @@
_stk_pos = (unsigned long)&_stk_pos; _stk_pos = (unsigned long)&_stk_pos;
if (STK_COMP(_stk_pos, SCHEME_STACK_BOUNDARY)) if (STK_COMP(_stk_pos, SCHEME_STACK_BOUNDARY)
&& !scheme_no_stack_overflow)
# endif # endif
#endif #endif

View File

@ -8291,6 +8291,111 @@ void scheme_start_itimer_thread(long usec)
#endif #endif
#ifdef OS_X
/* Sleep-in-thread support needed for GUIs Mac OS X.
To merge waiting on a CoreFoundation event with a select(), an embedding
application can attach a single socket to an event callback, and then
create a Mac thread to call the usual sleep and write to the socket when
data is available. */
#ifdef MZ_PRECISE_GC
START_XFORM_SKIP;
#endif
typedef struct {
pthread_mutex_t lock;
pthread_cond_t cond;
int count;
} pt_sema_t;
void pt_sema_init(pt_sema_t *sem)
{
pthread_mutex_init(&sem->lock, NULL);
pthread_cond_init(&sem->cond, NULL);
sem->count = 0;
}
void pt_sema_wait(pt_sema_t *sem)
{
pthread_mutex_lock(&sem->lock);
while (sem->count <= 0)
pthread_cond_wait(&sem->cond, &sem->lock);
sem->count--;
pthread_mutex_unlock(&sem->lock);
}
void pt_sema_post(pt_sema_t *sem)
{
pthread_mutex_lock(&sem->lock);
sem->count++;
if (sem->count > 0)
pthread_cond_signal(&sem->cond);
pthread_mutex_unlock(&sem->lock);
}
static pthread_t watcher;
static pt_sema_t sleeping_sema, done_sema;
static float sleep_secs;
static int slept_fd;
static void *sleep_fds;
static void (*sleep_sleep)(float seconds, void *fds);
static void *do_watch()
{
while (1) {
pt_sema_wait(&sleeping_sema);
sleep_sleep(sleep_secs, sleep_fds);
write(slept_fd, "y", 1);
pt_sema_post(&done_sema);
}
}
void scheme_start_sleeper_thread(void (*given_sleep)(float seconds, void *fds), float secs, void *fds, int hit_fd)
{
if (!watcher) {
pt_sema_init(&sleeping_sema);
pt_sema_init(&done_sema);
if (pthread_create(&watcher, NULL, do_watch, NULL)) {
scheme_log_abort("pthread_create failed");
abort();
}
}
sleep_sleep = given_sleep;
sleep_fds = fds;
sleep_secs = secs;
slept_fd = hit_fd;
pt_sema_post(&sleeping_sema);
}
void scheme_end_sleeper_thread()
{
scheme_signal_received();
pt_sema_wait(&done_sema);
/* Clear external event flag */
if (external_event_fd) {
char buf[10];
read(external_event_fd, buf, 10);
}
}
#ifdef MZ_PRECISE_GC
END_XFORM_SKIP;
#endif
#else
void scheme_start_sleeper_thread(void *fds, int hit_fd);
void scheme_end_sleeper_thread();
#endif
/*========================================================================*/ /*========================================================================*/
/* memory debugging help */ /* memory debugging help */
/*========================================================================*/ /*========================================================================*/

View File

@ -82,6 +82,8 @@ MZ_EXTERN Scheme_Thread *scheme_get_current_thread();
MZ_EXTERN void scheme_start_atomic(void); MZ_EXTERN void scheme_start_atomic(void);
MZ_EXTERN void scheme_end_atomic(void); MZ_EXTERN void scheme_end_atomic(void);
MZ_EXTERN void scheme_end_atomic_no_swap(void); MZ_EXTERN void scheme_end_atomic_no_swap(void);
MZ_EXTERN void scheme_start_in_scheduler(void);
MZ_EXTERN void scheme_end_in_scheduler(void);
MZ_EXTERN void scheme_out_of_fuel(void); MZ_EXTERN void scheme_out_of_fuel(void);
@ -120,6 +122,9 @@ MZ_EXTERN int scheme_in_main_thread(void);
MZ_EXTERN void scheme_cancel_sleep(void); MZ_EXTERN void scheme_cancel_sleep(void);
MZ_EXTERN void scheme_start_sleeper_thread(void (*mzsleep)(float seconds, void *fds), float secs, void *fds, int hit_fd);
MZ_EXTERN void scheme_end_sleeper_thread();
MZ_EXTERN Scheme_Object *scheme_make_thread_cell(Scheme_Object *def_val, int inherited); MZ_EXTERN Scheme_Object *scheme_make_thread_cell(Scheme_Object *def_val, int inherited);
MZ_EXTERN Scheme_Object *scheme_thread_cell_get(Scheme_Object *cell, Scheme_Thread_Cell_Table *cells); MZ_EXTERN Scheme_Object *scheme_thread_cell_get(Scheme_Object *cell, Scheme_Thread_Cell_Table *cells);
MZ_EXTERN void scheme_thread_cell_set(Scheme_Object *cell, Scheme_Thread_Cell_Table *cells, Scheme_Object *v); MZ_EXTERN void scheme_thread_cell_set(Scheme_Object *cell, Scheme_Thread_Cell_Table *cells, Scheme_Object *v);

View File

@ -66,6 +66,8 @@ Scheme_Thread *(*scheme_get_current_thread)();
void (*scheme_start_atomic)(void); void (*scheme_start_atomic)(void);
void (*scheme_end_atomic)(void); void (*scheme_end_atomic)(void);
void (*scheme_end_atomic_no_swap)(void); void (*scheme_end_atomic_no_swap)(void);
void (*scheme_start_in_scheduler)(void);
void (*scheme_end_in_scheduler)(void);
void (*scheme_out_of_fuel)(void); void (*scheme_out_of_fuel)(void);
Scheme_Object *(*scheme_thread)(Scheme_Object *thunk); Scheme_Object *(*scheme_thread)(Scheme_Object *thunk);
Scheme_Object *(*scheme_thread_w_details)(Scheme_Object *thunk, Scheme_Object *(*scheme_thread_w_details)(Scheme_Object *thunk,
@ -95,6 +97,8 @@ void (*scheme_wait_input_allowed)(Scheme_Input_Port *port, int nonblock);
int (*scheme_unless_ready)(Scheme_Object *unless); int (*scheme_unless_ready)(Scheme_Object *unless);
int (*scheme_in_main_thread)(void); int (*scheme_in_main_thread)(void);
void (*scheme_cancel_sleep)(void); void (*scheme_cancel_sleep)(void);
void (*scheme_start_sleeper_thread)(void (*mzsleep)(float seconds, void *fds), float secs, void *fds, int hit_fd);
void (*scheme_end_sleeper_thread)();
Scheme_Object *(*scheme_make_thread_cell)(Scheme_Object *def_val, int inherited); Scheme_Object *(*scheme_make_thread_cell)(Scheme_Object *def_val, int inherited);
Scheme_Object *(*scheme_thread_cell_get)(Scheme_Object *cell, Scheme_Thread_Cell_Table *cells); Scheme_Object *(*scheme_thread_cell_get)(Scheme_Object *cell, Scheme_Thread_Cell_Table *cells);
void (*scheme_thread_cell_set)(Scheme_Object *cell, Scheme_Thread_Cell_Table *cells, Scheme_Object *v); void (*scheme_thread_cell_set)(Scheme_Object *cell, Scheme_Thread_Cell_Table *cells, Scheme_Object *v);

View File

@ -31,6 +31,8 @@
scheme_extension_table->scheme_start_atomic = scheme_start_atomic; scheme_extension_table->scheme_start_atomic = scheme_start_atomic;
scheme_extension_table->scheme_end_atomic = scheme_end_atomic; scheme_extension_table->scheme_end_atomic = scheme_end_atomic;
scheme_extension_table->scheme_end_atomic_no_swap = scheme_end_atomic_no_swap; scheme_extension_table->scheme_end_atomic_no_swap = scheme_end_atomic_no_swap;
scheme_extension_table->scheme_start_in_scheduler = scheme_start_in_scheduler;
scheme_extension_table->scheme_end_in_scheduler = scheme_end_in_scheduler;
scheme_extension_table->scheme_out_of_fuel = scheme_out_of_fuel; scheme_extension_table->scheme_out_of_fuel = scheme_out_of_fuel;
scheme_extension_table->scheme_thread = scheme_thread; scheme_extension_table->scheme_thread = scheme_thread;
scheme_extension_table->scheme_thread_w_details = scheme_thread_w_details; scheme_extension_table->scheme_thread_w_details = scheme_thread_w_details;
@ -51,6 +53,8 @@
scheme_extension_table->scheme_unless_ready = scheme_unless_ready; scheme_extension_table->scheme_unless_ready = scheme_unless_ready;
scheme_extension_table->scheme_in_main_thread = scheme_in_main_thread; scheme_extension_table->scheme_in_main_thread = scheme_in_main_thread;
scheme_extension_table->scheme_cancel_sleep = scheme_cancel_sleep; scheme_extension_table->scheme_cancel_sleep = scheme_cancel_sleep;
scheme_extension_table->scheme_start_sleeper_thread = scheme_start_sleeper_thread;
scheme_extension_table->scheme_end_sleeper_thread = scheme_end_sleeper_thread;
scheme_extension_table->scheme_make_thread_cell = scheme_make_thread_cell; scheme_extension_table->scheme_make_thread_cell = scheme_make_thread_cell;
scheme_extension_table->scheme_thread_cell_get = scheme_thread_cell_get; scheme_extension_table->scheme_thread_cell_get = scheme_thread_cell_get;
scheme_extension_table->scheme_thread_cell_set = scheme_thread_cell_set; scheme_extension_table->scheme_thread_cell_set = scheme_thread_cell_set;

View File

@ -31,6 +31,8 @@
#define scheme_start_atomic (scheme_extension_table->scheme_start_atomic) #define scheme_start_atomic (scheme_extension_table->scheme_start_atomic)
#define scheme_end_atomic (scheme_extension_table->scheme_end_atomic) #define scheme_end_atomic (scheme_extension_table->scheme_end_atomic)
#define scheme_end_atomic_no_swap (scheme_extension_table->scheme_end_atomic_no_swap) #define scheme_end_atomic_no_swap (scheme_extension_table->scheme_end_atomic_no_swap)
#define scheme_start_in_scheduler (scheme_extension_table->scheme_start_in_scheduler)
#define scheme_end_in_scheduler (scheme_extension_table->scheme_end_in_scheduler)
#define scheme_out_of_fuel (scheme_extension_table->scheme_out_of_fuel) #define scheme_out_of_fuel (scheme_extension_table->scheme_out_of_fuel)
#define scheme_thread (scheme_extension_table->scheme_thread) #define scheme_thread (scheme_extension_table->scheme_thread)
#define scheme_thread_w_details (scheme_extension_table->scheme_thread_w_details) #define scheme_thread_w_details (scheme_extension_table->scheme_thread_w_details)
@ -51,6 +53,8 @@
#define scheme_unless_ready (scheme_extension_table->scheme_unless_ready) #define scheme_unless_ready (scheme_extension_table->scheme_unless_ready)
#define scheme_in_main_thread (scheme_extension_table->scheme_in_main_thread) #define scheme_in_main_thread (scheme_extension_table->scheme_in_main_thread)
#define scheme_cancel_sleep (scheme_extension_table->scheme_cancel_sleep) #define scheme_cancel_sleep (scheme_extension_table->scheme_cancel_sleep)
#define scheme_start_sleeper_thread (scheme_extension_table->scheme_start_sleeper_thread)
#define scheme_end_sleeper_thread (scheme_extension_table->scheme_end_sleeper_thread)
#define scheme_make_thread_cell (scheme_extension_table->scheme_make_thread_cell) #define scheme_make_thread_cell (scheme_extension_table->scheme_make_thread_cell)
#define scheme_thread_cell_get (scheme_extension_table->scheme_thread_cell_get) #define scheme_thread_cell_get (scheme_extension_table->scheme_thread_cell_get)
#define scheme_thread_cell_set (scheme_extension_table->scheme_thread_cell_set) #define scheme_thread_cell_set (scheme_extension_table->scheme_thread_cell_set)

View File

@ -362,6 +362,8 @@ extern mz_proc_thread *scheme_master_proc_thread;
extern THREAD_LOCAL mz_proc_thread *proc_thread_self; extern THREAD_LOCAL mz_proc_thread *proc_thread_self;
#endif #endif
extern int scheme_no_stack_overflow;
typedef struct Scheme_Thread_Set { typedef struct Scheme_Thread_Set {
Scheme_Object so; Scheme_Object so;
struct Scheme_Thread_Set *parent; struct Scheme_Thread_Set *parent;

View File

@ -13,12 +13,12 @@
consistently.) consistently.)
*/ */
#define MZSCHEME_VERSION "4.1.3.8" #define MZSCHEME_VERSION "4.1.3.9"
#define MZSCHEME_VERSION_X 4 #define MZSCHEME_VERSION_X 4
#define MZSCHEME_VERSION_Y 1 #define MZSCHEME_VERSION_Y 1
#define MZSCHEME_VERSION_Z 3 #define MZSCHEME_VERSION_Z 3
#define MZSCHEME_VERSION_W 8 #define MZSCHEME_VERSION_W 9
#define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y) #define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y)
#define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W) #define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W)

View File

@ -220,6 +220,7 @@ static int missed_context_switch = 0;
static int have_activity = 0; static int have_activity = 0;
int scheme_active_but_sleeping = 0; int scheme_active_but_sleeping = 0;
static int thread_ended_with_activity; static int thread_ended_with_activity;
int scheme_no_stack_overflow;
static int needs_sleep_cancelled; static int needs_sleep_cancelled;
@ -3437,13 +3438,16 @@ static int check_sleep(int need_activity, int sleep_now)
{ {
Scheme_Thread *p, *p2; Scheme_Thread *p, *p2;
int end_with_act; int end_with_act;
#if defined(USING_FDS) #if defined(USING_FDS)
DECL_FDSET(set, 3); DECL_FDSET(set, 3);
fd_set *set1, *set2; fd_set *set1, *set2;
#endif #endif
void *fds; void *fds;
if (scheme_no_stack_overflow)
return 0;
/* Is everything blocked? */ /* Is everything blocked? */
if (!do_atomic) { if (!do_atomic) {
p = scheme_first_thread; p = scheme_first_thread;
@ -3641,7 +3645,7 @@ static int can_break_param(Scheme_Thread *p)
int scheme_can_break(Scheme_Thread *p) int scheme_can_break(Scheme_Thread *p)
{ {
if (!p->suspend_break) { if (!p->suspend_break && !scheme_no_stack_overflow) {
return can_break_param(p); return can_break_param(p);
} else } else
return 0; return 0;
@ -4361,6 +4365,18 @@ void scheme_end_atomic_no_swap(void)
--do_atomic; --do_atomic;
} }
void scheme_start_in_scheduler(void)
{
do_atomic++;
scheme_no_stack_overflow++;
}
void scheme_end_in_scheduler(void)
{
--do_atomic;
--scheme_no_stack_overflow;
}
void scheme_end_atomic(void) void scheme_end_atomic(void)
{ {
scheme_end_atomic_no_swap(); scheme_end_atomic_no_swap();