add custodian-tidy-all

This commit is contained in:
Matthew Flatt 2014-05-07 06:04:53 -06:00
parent 0ba8cd9586
commit 1bd604073a
25 changed files with 1063 additions and 694 deletions

View File

@ -24,7 +24,8 @@ automatically directed to shut down its managed values as well.}
@defproc[(custodian-shutdown-all [cust custodian?]) void?]{
@margin-note{In GRacket, @|eventspaces| managed by @racket[cust] are also
@margin-note{In @racketmodname[racket/gui/base],
@|eventspaces| managed by @racket[cust] are also
shut down.}
Closes all @tech{file-stream ports}, @tech{TCP ports}, @tech{TCP
@ -40,7 +41,8 @@ thread.}
@defparam[current-custodian cust custodian?]{
@margin-note{In GRacket, custodians also manage @|eventspaces|.}
@margin-note{Custodians also manage @|eventspaces|
from @racketmodname[racket/gui/base].}
A @tech{parameter} that determines a custodian that assumes responsibility
for newly created threads, @tech{file-stream ports}, TCP ports,
@ -126,3 +128,60 @@ The @tech{custodian box} becomes ready when its custodian is shut down;
@defproc[(custodian-box-value [cb custodian-box?]) any]{Returns the
value in the given @tech{custodian box}, or @racket[#f] if the value
has been removed.}
@defproc[(custodian-tidy-callback? [v any/c]) boolean?]{
Returns @racket[#t] if @racket[v] represents the registration of a
@tech{tidy callback}, @racket[#f] otherwise.
@history[#:added "6.0.1.7"]}
@defproc[(custodian-add-tidy! [cust custodian?]
[proc (custodian-tidy-callback? . -> . any)])
custodian-tidy-callback?]{
Registers @racket[proc] as a @tech{tidy callback} in @racket[cust], so
that @racket[proc] is called when @racket[custodian-tidy-all] is
applied to @racket[cust] or any of its superordinates.
The result value represents the registration of the callback and can
be used with @racket[custodian-remove-tidy!] to unregister the callback.
When @racket[proc] is called as a @tech{tidy callback}, it is passed
the same value that is returned by @racket[custodian-add-tidy!] so
that @racket[proc] can conveniently unregister itself. The call of
@racket[proc] is within a @tech{continuation barrier}.
All registered @tech{tidy callbacks} are preserved in @racket[cust]
until they are explicitly removed with @racket[custodian-remove-tidy!]
or the custodian is shut down with @racket[custodian-shutdown-all].
If @racket[cust] has been shut down already, the @exnraise[exn:fail:contract].
@history[#:added "6.0.1.7"]}
@defproc[(custodian-remove-tidy! [tidy custodian-tidy-callback?]) void?]{
Unregisters the @tech{tidy callback} that was registered by the
@racket[custodian-add-tidy!] call that produced @racket[tidy].
If the registration represented by @racket[tidy] has been removed already,
then @racket[custodian-remove-tidy!] has no effect.
@history[#:added "6.0.1.7"]}
@defproc[(custodian-tidy-all [cust custodian?]) void?]{
Calls all @tech{tidy callbacks} registered with @racket[cust] (and its
subordinates).
The @tech{tidy callbacks} to call are collected from @racket[cust]
before the first one is called. If a @tech{tidy callback} registers a
new @tech{tidy callback}, the new one is @emph{not} called. If a
@tech{tidy callback} raises an exception or otherwise escapes, then
the remaining @tech{tidy callbacks} are not called.
@history[#:added "6.0.1.7"]}

View File

@ -833,7 +833,8 @@ created, it is placed under the management of the @deftech{current
custodian} as determined by the @racket[current-custodian]
@tech{parameter}.
@margin-note{In GRacket, custodians also manage eventspaces.}
@margin-note{Custodians also manage eventspaces from
@racketmodname[racket/gui/base].}
Except for the root custodian, every @tech{custodian} itself is
managed by a @tech{custodian}, so that custodians form a hierarchy.
@ -849,6 +850,14 @@ down, if a procedure is called that attempts to create a managed resource (e.g.,
@racket[open-input-file], @racket[thread]), then the
@exnraise[exn:fail:contract].
A @tech{custodian} also supports @deftech{tidy callbacks}, which are
normally triggered just before a Racket process or @tech{place} exits.
For example, a @tech{tidy callback} might flush an output port's
buffer. A tidying custodian calls its own callbacks as well as the
tidy callbacks of its subcustodians, but there is no guarantee that a
tidy callback will be called before exit. Shutting down a
custodian does @emph{not} call tidy callbacks.
A thread can have multiple managing custodians, and a suspended thread
created with @racket[thread/suspend-to-kill] can have zero
custodians. Extra custodians become associated with a thread through

View File

@ -16,7 +16,8 @@ A @tech{parameter} that determines the current @deftech{exit handler}. The
@tech{exit handler} is called by @racket[exit].
The default @tech{exit handler} in the Racket executable
takes any argument and shuts down the OS-level Racket process. The
takes any argument, calls @racket[custodian-tidy-all] on the root custodian,
and shuts down the OS-level Racket process. The
argument is used as the OS-level exit code if it is an exact integer
between @racket[1] and @racket[255] (which normally means
``failure''); otherwise, the exit code is @racket[0], (which normally

View File

@ -43,7 +43,8 @@ recognizes file-stream ports.
When an input or output file-stream port is created, it is placed into
the management of the current custodian (see
@secref["custodians"]).
@secref["custodians"]). In the case of an output port, a @tech{tidy
callback} is registered to flush the port.
@defproc[(open-input-file [path path-string?]
[#:mode mode-flag (or/c 'binary 'text) 'binary]

View File

@ -0,0 +1,49 @@
#lang racket/base
(require racket/place)
(define (go)
(place
pch
(custodian-add-tidy! (current-custodian)
(lambda (e)
(custodian-remove-tidy! e)
(place-channel-put pch 'done)))
(place-channel-put pch 'ready)
(define mode (place-channel-get pch))
(case mode
[(exit) (exit 2)]
[(error)
(error-display-handler void)
(custodian-add-tidy! (current-custodian)
(lambda (e)
(error "fail")))]
[else (void)])))
(module+ main
(require rackunit)
(define p1 (go))
(check-equal? 'ready (place-channel-get p1))
(place-channel-put p1 'normal)
(check-equal? 0 (place-wait p1))
(check-equal? 'done (place-channel-get p1))
(define p2 (go))
(check-equal? 'ready (place-channel-get p2))
(place-channel-put p2 'exit)
(check-equal? 2 (place-wait p2))
(check-equal? 'done (place-channel-get p2))
(define p3 (go))
(check-equal? 'ready (place-channel-get p3))
(place-kill p3)
(check-equal? 1 (place-wait p3))
(check-equal? #f (sync/timeout 0.1 p3))
(define p4 (go))
(check-equal? 'ready (place-channel-get p4))
(place-channel-put p4 'error)
(check-equal? 1 (place-wait p4)))
(module+ test
(require (submod ".." main)))

View File

@ -1179,6 +1179,68 @@
(test #f thread-running? t1)
(test #f thread-running? t2))
;; ----------------------------------------
;; custodian exits
(let ()
(define c (make-custodian))
(define done 0)
(define e (custodian-add-tidy! c (lambda (e) (set! done (add1 done)))))
(test #t custodian-tidy-callback? e)
(test #f custodian-tidy-callback? c)
(test #f ormap custodian-tidy-callback?
(custodian-managed-list c (current-custodian)))
(custodian-remove-tidy! e)
(custodian-remove-tidy! e) ; no-op
(custodian-tidy-all c)
(test 0 values done)
(define e2 (custodian-add-tidy! c (lambda (e) (set! done (add1 done)))))
(custodian-tidy-all c)
(test 1 values done)
(custodian-remove-tidy! e2)
(define e3 (custodian-add-tidy! (make-custodian c) (lambda (e) (set! done (add1 done)))))
(custodian-tidy-all c)
(test 2 values done)
(custodian-tidy-all c)
(test 3 values done)
(custodian-remove-tidy! e3)
(custodian-add-tidy! c (lambda (e)
(custodian-remove-tidy! e)
(set! done (add1 done))
(custodian-add-tidy! c (lambda (e)
(custodian-remove-tidy! e)
(set! done (add1 done))))))
(custodian-tidy-all c)
(test 4 values done)
(custodian-tidy-all c)
(test 5 values done)
(custodian-tidy-all c)
(test 5 values done)
(define e5 (custodian-add-tidy! c (lambda (e) (error "oops1"))))
(err/rt-test (custodian-tidy-all c) exn:fail?)
(err/rt-test (custodian-tidy-all c) exn:fail?)
(custodian-remove-tidy! e5)
(test (void) custodian-tidy-all c)
(custodian-add-tidy! c (lambda (e) (set! done (add1 done))))
(custodian-shutdown-all c)
(test 5 values done)
(custodian-tidy-all c)
(test 5 values done)
(err/rt-test (custodian-add-tidy! c (lambda (e) 'x))))
;; ----------------------------------------
;; Check that a terminated thread cleans up ownership

View File

@ -602,6 +602,9 @@ static int finish_cmd_line_run(FinishArgs *fa, Repl_Proc repl)
}
#endif
if (scheme_tidy_managed(NULL, 1))
exit_val = 1;
return exit_val;
}

View File

@ -73,6 +73,7 @@ EXPORTS
scheme_custodian_is_available
scheme_remove_managed
scheme_close_managed
scheme_tidy_managed
scheme_schedule_custodian_close
scheme_add_custodian_extractor
scheme_add_atexit_closer

View File

@ -73,6 +73,7 @@ EXPORTS
scheme_custodian_is_available
scheme_remove_managed
scheme_close_managed
scheme_tidy_managed
scheme_schedule_custodian_close
scheme_add_custodian_extractor
scheme_add_atexit_closer

View File

@ -71,6 +71,7 @@ scheme_custodian_check_available
scheme_custodian_is_available
scheme_remove_managed
scheme_close_managed
scheme_tidy_managed
scheme_schedule_custodian_close
scheme_add_custodian_extractor
scheme_add_atexit_closer

View File

@ -71,6 +71,7 @@ scheme_custodian_check_available
scheme_custodian_is_available
scheme_remove_managed
scheme_close_managed
scheme_tidy_managed
scheme_schedule_custodian_close
scheme_add_custodian_extractor
scheme_add_atexit_closer

File diff suppressed because it is too large Load Diff

View File

@ -3358,6 +3358,8 @@ def_exit_handler_proc(int argc, Scheme_Object *argv[])
} else
status = 0;
scheme_tidy_managed(NULL, 0);
if (scheme_exit)
scheme_exit(status);
else

View File

@ -2599,11 +2599,17 @@ static void terminate_current_place(Scheme_Object *result)
Scheme_Place_Object *place_obj;
place_obj = place_object;
place_object = NULL;
mzrt_mutex_lock(place_obj->lock);
place_obj_die = place_obj->die;
mzrt_mutex_unlock(place_obj->lock);
if (!place_obj_die) {
if (scheme_tidy_managed(NULL, 1))
result = scheme_make_integer(1);
}
place_object = NULL;
/*printf("Leavin place: proc thread id%u\n", ptid);*/

View File

@ -8390,14 +8390,19 @@ make_fd_output_port(intptr_t fd, Scheme_Object *name, int regfile, int win_textm
static void flush_if_output_fds(Scheme_Object *o, Scheme_Close_Custodian_Client *f, void *data)
{
if (SCHEME_OUTPUT_PORTP(o)) {
Scheme_Output_Port *op;
op = scheme_output_port_record(o);
if (SAME_OBJ(op->sub_type, fd_output_port_type))
scheme_flush_output(o);
if (SCHEME_OUTPORTP(o)) {
scheme_flush_if_output_fds(o);
}
}
void scheme_flush_if_output_fds(Scheme_Object *o)
{
Scheme_Output_Port *op;
op = scheme_output_port_record(o);
if (SAME_OBJ(op->sub_type, fd_output_port_type))
scheme_flush_output(o);
}
#ifdef WINDOWS_FILE_HANDLES
static long WINAPI WindowsFDWriter(Win_FD_Output_Thread *oth)

View File

@ -163,6 +163,7 @@ MZ_EXTERN void scheme_custodian_check_available(Scheme_Custodian *m, const char
MZ_EXTERN int scheme_custodian_is_available(Scheme_Custodian *m);
MZ_EXTERN void scheme_remove_managed(Scheme_Custodian_Reference *m, Scheme_Object *o);
MZ_EXTERN void scheme_close_managed(Scheme_Custodian *m);
MZ_EXTERN int scheme_tidy_managed(Scheme_Custodian *m, int catch_errors);
MZ_EXTERN void scheme_schedule_custodian_close(Scheme_Custodian *c);
MZ_EXTERN void scheme_add_custodian_extractor(Scheme_Type t, Scheme_Custodian_Extractor e);

View File

@ -116,6 +116,7 @@ void (*scheme_custodian_check_available)(Scheme_Custodian *m, const char *who, c
int (*scheme_custodian_is_available)(Scheme_Custodian *m);
void (*scheme_remove_managed)(Scheme_Custodian_Reference *m, Scheme_Object *o);
void (*scheme_close_managed)(Scheme_Custodian *m);
int (*scheme_tidy_managed)(Scheme_Custodian *m, int catch_errors);
void (*scheme_schedule_custodian_close)(Scheme_Custodian *c);
void (*scheme_add_custodian_extractor)(Scheme_Type t, Scheme_Custodian_Extractor e);
void (*scheme_add_atexit_closer)(Scheme_Exit_Closer_Func f);

View File

@ -79,6 +79,7 @@
scheme_extension_table->scheme_custodian_is_available = scheme_custodian_is_available;
scheme_extension_table->scheme_remove_managed = scheme_remove_managed;
scheme_extension_table->scheme_close_managed = scheme_close_managed;
scheme_extension_table->scheme_tidy_managed = scheme_tidy_managed;
scheme_extension_table->scheme_schedule_custodian_close = scheme_schedule_custodian_close;
scheme_extension_table->scheme_add_custodian_extractor = scheme_add_custodian_extractor;
scheme_extension_table->scheme_add_atexit_closer = scheme_add_atexit_closer;

View File

@ -79,6 +79,7 @@
#define scheme_custodian_is_available (scheme_extension_table->scheme_custodian_is_available)
#define scheme_remove_managed (scheme_extension_table->scheme_remove_managed)
#define scheme_close_managed (scheme_extension_table->scheme_close_managed)
#define scheme_tidy_managed (scheme_extension_table->scheme_tidy_managed)
#define scheme_schedule_custodian_close (scheme_extension_table->scheme_schedule_custodian_close)
#define scheme_add_custodian_extractor (scheme_extension_table->scheme_add_custodian_extractor)
#define scheme_add_atexit_closer (scheme_extension_table->scheme_add_atexit_closer)

View File

@ -14,7 +14,7 @@
#define USE_COMPILED_STARTUP 1
#define EXPECTED_PRIM_COUNT 1117
#define EXPECTED_PRIM_COUNT 1121
#define EXPECTED_UNSAFE_COUNT 106
#define EXPECTED_FLFXNUM_COUNT 69
#define EXPECTED_EXTFL_COUNT 45

View File

@ -3840,6 +3840,7 @@ extern Scheme_Object *scheme_tcp_output_port_type;
THREAD_LOCAL_DECL(extern int scheme_force_port_closed);
void scheme_flush_orig_outputs(void);
void scheme_flush_if_output_fds(Scheme_Object *o);
Scheme_Object *scheme_file_stream_port_p(int, Scheme_Object *[]);
Scheme_Object *scheme_terminal_port_p(int, Scheme_Object *[]);
Scheme_Object *scheme_do_open_input_file(char *name, int offset, int argc, Scheme_Object *argv[],

View File

@ -13,12 +13,12 @@
consistently.)
*/
#define MZSCHEME_VERSION "6.0.1.6"
#define MZSCHEME_VERSION "6.0.1.7"
#define MZSCHEME_VERSION_X 6
#define MZSCHEME_VERSION_Y 0
#define MZSCHEME_VERSION_Z 1
#define MZSCHEME_VERSION_W 6
#define MZSCHEME_VERSION_W 7
#define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y)
#define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W)

View File

@ -211,86 +211,87 @@ enum {
scheme_environment_variables_type, /* 187 */
scheme_filesystem_change_evt_type, /* 188 */
scheme_ctype_type, /* 189 */
scheme_custodian_tidy_type, /* 190 */
#ifdef MZTAG_REQUIRED
_scheme_last_normal_type_, /* 190 */
_scheme_last_normal_type_, /* 191 */
scheme_rt_weak_array, /* 191 */
scheme_rt_weak_array, /* 192 */
scheme_rt_comp_env, /* 192 */
scheme_rt_constant_binding, /* 193 */
scheme_rt_resolve_info, /* 194 */
scheme_rt_unresolve_info, /* 195 */
scheme_rt_optimize_info, /* 196 */
scheme_rt_compile_info, /* 197 */
scheme_rt_cont_mark, /* 198 */
scheme_rt_saved_stack, /* 199 */
scheme_rt_reply_item, /* 200 */
scheme_rt_closure_info, /* 201 */
scheme_rt_overflow, /* 202 */
scheme_rt_overflow_jmp, /* 203 */
scheme_rt_meta_cont, /* 204 */
scheme_rt_dyn_wind_cell, /* 205 */
scheme_rt_dyn_wind_info, /* 206 */
scheme_rt_dyn_wind, /* 207 */
scheme_rt_dup_check, /* 208 */
scheme_rt_thread_memory, /* 209 */
scheme_rt_input_file, /* 210 */
scheme_rt_input_fd, /* 211 */
scheme_rt_oskit_console_input, /* 212 */
scheme_rt_tested_input_file, /* 213 */
scheme_rt_tested_output_file, /* 214 */
scheme_rt_indexed_string, /* 215 */
scheme_rt_output_file, /* 216 */
scheme_rt_load_handler_data, /* 217 */
scheme_rt_pipe, /* 218 */
scheme_rt_beos_process, /* 219 */
scheme_rt_system_child, /* 220 */
scheme_rt_tcp, /* 221 */
scheme_rt_write_data, /* 222 */
scheme_rt_tcp_select_info, /* 223 */
scheme_rt_param_data, /* 224 */
scheme_rt_will, /* 225 */
scheme_rt_linker_name, /* 226 */
scheme_rt_param_map, /* 227 */
scheme_rt_finalization, /* 228 */
scheme_rt_finalizations, /* 229 */
scheme_rt_cpp_object, /* 230 */
scheme_rt_cpp_array_object, /* 231 */
scheme_rt_stack_object, /* 232 */
scheme_rt_preallocated_object, /* 233 */
scheme_thread_hop_type, /* 234 */
scheme_rt_srcloc, /* 235 */
scheme_rt_evt, /* 236 */
scheme_rt_syncing, /* 237 */
scheme_rt_comp_prefix, /* 238 */
scheme_rt_user_input, /* 239 */
scheme_rt_user_output, /* 240 */
scheme_rt_compact_port, /* 241 */
scheme_rt_read_special_dw, /* 242 */
scheme_rt_regwork, /* 243 */
scheme_rt_rx_lazy_string, /* 244 */
scheme_rt_buf_holder, /* 245 */
scheme_rt_parameterization, /* 246 */
scheme_rt_print_params, /* 247 */
scheme_rt_read_params, /* 248 */
scheme_rt_native_code, /* 249 */
scheme_rt_native_code_plus_case, /* 250 */
scheme_rt_jitter_data, /* 251 */
scheme_rt_module_exports, /* 252 */
scheme_rt_delay_load_info, /* 253 */
scheme_rt_marshal_info, /* 254 */
scheme_rt_unmarshal_info, /* 255 */
scheme_rt_runstack, /* 256 */
scheme_rt_sfs_info, /* 257 */
scheme_rt_validate_clearing, /* 258 */
scheme_rt_avl_node, /* 259 */
scheme_rt_lightweight_cont, /* 260 */
scheme_rt_export_info, /* 261 */
scheme_rt_cont_jmp, /* 262 */
scheme_rt_letrec_check_frame, /* 263 */
scheme_rt_comp_env, /* 193 */
scheme_rt_constant_binding, /* 194 */
scheme_rt_resolve_info, /* 195 */
scheme_rt_unresolve_info, /* 196 */
scheme_rt_optimize_info, /* 197 */
scheme_rt_compile_info, /* 198 */
scheme_rt_cont_mark, /* 199 */
scheme_rt_saved_stack, /* 200 */
scheme_rt_reply_item, /* 201 */
scheme_rt_closure_info, /* 202 */
scheme_rt_overflow, /* 203 */
scheme_rt_overflow_jmp, /* 204 */
scheme_rt_meta_cont, /* 205 */
scheme_rt_dyn_wind_cell, /* 206 */
scheme_rt_dyn_wind_info, /* 207 */
scheme_rt_dyn_wind, /* 208 */
scheme_rt_dup_check, /* 209 */
scheme_rt_thread_memory, /* 210 */
scheme_rt_input_file, /* 211 */
scheme_rt_input_fd, /* 212 */
scheme_rt_oskit_console_input, /* 213 */
scheme_rt_tested_input_file, /* 214 */
scheme_rt_tested_output_file, /* 215 */
scheme_rt_indexed_string, /* 216 */
scheme_rt_output_file, /* 217 */
scheme_rt_load_handler_data, /* 218 */
scheme_rt_pipe, /* 219 */
scheme_rt_beos_process, /* 220 */
scheme_rt_system_child, /* 221 */
scheme_rt_tcp, /* 222 */
scheme_rt_write_data, /* 223 */
scheme_rt_tcp_select_info, /* 224 */
scheme_rt_param_data, /* 225 */
scheme_rt_will, /* 226 */
scheme_rt_linker_name, /* 227 */
scheme_rt_param_map, /* 228 */
scheme_rt_finalization, /* 229 */
scheme_rt_finalizations, /* 230 */
scheme_rt_cpp_object, /* 231 */
scheme_rt_cpp_array_object, /* 232 */
scheme_rt_stack_object, /* 233 */
scheme_rt_preallocated_object, /* 234 */
scheme_thread_hop_type, /* 235 */
scheme_rt_srcloc, /* 236 */
scheme_rt_evt, /* 237 */
scheme_rt_syncing, /* 238 */
scheme_rt_comp_prefix, /* 239 */
scheme_rt_user_input, /* 240 */
scheme_rt_user_output, /* 241 */
scheme_rt_compact_port, /* 242 */
scheme_rt_read_special_dw, /* 243 */
scheme_rt_regwork, /* 244 */
scheme_rt_rx_lazy_string, /* 245 */
scheme_rt_buf_holder, /* 246 */
scheme_rt_parameterization, /* 247 */
scheme_rt_print_params, /* 248 */
scheme_rt_read_params, /* 249 */
scheme_rt_native_code, /* 250 */
scheme_rt_native_code_plus_case, /* 251 */
scheme_rt_jitter_data, /* 252 */
scheme_rt_module_exports, /* 253 */
scheme_rt_delay_load_info, /* 254 */
scheme_rt_marshal_info, /* 255 */
scheme_rt_unmarshal_info, /* 256 */
scheme_rt_runstack, /* 257 */
scheme_rt_sfs_info, /* 258 */
scheme_rt_validate_clearing, /* 259 */
scheme_rt_avl_node, /* 260 */
scheme_rt_lightweight_cont, /* 261 */
scheme_rt_export_info, /* 262 */
scheme_rt_cont_jmp, /* 263 */
scheme_rt_letrec_check_frame, /* 264 */
#endif
scheme_deferred_expr_type, /* 264 */
scheme_deferred_expr_type, /* 265 */
_scheme_last_type_
};

View File

@ -357,6 +357,10 @@ static Scheme_Object *make_custodian(int argc, Scheme_Object *argv[]);
static Scheme_Object *make_custodian_from_main(int argc, Scheme_Object *argv[]);
static Scheme_Object *custodian_p(int argc, Scheme_Object *argv[]);
static Scheme_Object *custodian_close_all(int argc, Scheme_Object *argv[]);
static Scheme_Object *custodian_tidy_all(int argc, Scheme_Object *argv[]);
static Scheme_Object *custodian_add_tidy(int argc, Scheme_Object *argv[]);
static Scheme_Object *custodian_remove_tidy(int argc, Scheme_Object *argv[]);
static Scheme_Object *custodian_tidy_p(int argc, Scheme_Object *argv[]);
static Scheme_Object *custodian_to_list(int argc, Scheme_Object *argv[]);
static Scheme_Object *current_custodian(int argc, Scheme_Object *argv[]);
static Scheme_Object *make_custodian_box(int argc, Scheme_Object *argv[]);
@ -530,6 +534,10 @@ void scheme_init_thread(Scheme_Env *env)
GLOBAL_PRIM_W_ARITY("make-custodian" , make_custodian , 0, 1, env);
GLOBAL_FOLDING_PRIM("custodian?" , custodian_p , 1, 1, 1 , env);
GLOBAL_PRIM_W_ARITY("custodian-shutdown-all", custodian_close_all , 1, 1, env);
GLOBAL_PRIM_W_ARITY("custodian-tidy-all" , custodian_tidy_all , 1, 1, env);
GLOBAL_PRIM_W_ARITY("custodian-add-tidy!" , custodian_add_tidy , 2, 2, env);
GLOBAL_PRIM_W_ARITY("custodian-remove-tidy!", custodian_remove_tidy, 1, 1, env);
GLOBAL_PRIM_W_ARITY("custodian-tidy-callback?", custodian_tidy_p , 1, 1, env);
GLOBAL_PRIM_W_ARITY("custodian-managed-list", custodian_to_list , 2, 2, env);
GLOBAL_PRIM_W_ARITY("make-custodian-box" , make_custodian_box , 2, 2, env);
GLOBAL_PRIM_W_ARITY("custodian-box-value" , custodian_box_value , 1, 1, env);
@ -1400,7 +1408,7 @@ Scheme_Thread *scheme_do_close_managed(Scheme_Custodian *m, Scheme_Exit_Closer_F
}
}
}
} else {
} else if (f) {
f(o, data);
}
}
@ -1462,7 +1470,6 @@ static void do_close_managed(Scheme_Custodian *m)
else
scheme_thread_block(0.0);
}
}
void scheme_close_managed(Scheme_Custodian *m)
@ -1474,6 +1481,97 @@ void scheme_close_managed(Scheme_Custodian *m)
scheme_current_thread->ran_some = 1;
}
static Scheme_Object *get_tidy_managed(Scheme_Custodian *m)
{
Scheme_Custodian *c, *start;
Scheme_Object *o, *r = scheme_null;
int i;
if (!m)
m = main_custodian;
if (m->shut_down)
return scheme_null;
for (c = m; CUSTODIAN_FAM(c->children); ) {
for (c = CUSTODIAN_FAM(c->children); CUSTODIAN_FAM(c->sibling); ) {
c = CUSTODIAN_FAM(c->sibling);
}
}
start = m;
m = c;
while (1) {
for (i = 0; i < m->count; i++) {
if (m->boxes[i]) {
o = xCUSTODIAN_FAM(m->boxes[i]);
if (o && (SCHEME_OUTPORTP(o)
|| SAME_TYPE(SCHEME_TYPE(o), scheme_custodian_tidy_type))) {
r = scheme_make_pair(o, r);
SCHEME_USE_FUEL(1);
}
}
}
if (SAME_OBJ(m, start))
break;
m = CUSTODIAN_FAM(m->global_prev);
if (!m) {
/* custodian was shut down? */
break;
}
}
return r;
}
int scheme_tidy_managed(Scheme_Custodian *m, int catch_errors)
{
Scheme_Object *r, *o;
Scheme_Thread *p;
mz_jmp_buf * volatile saved_error_buf;
mz_jmp_buf new_error_buf;
volatile int escaped = 0;
if (catch_errors) {
p = scheme_current_thread;
saved_error_buf = p->error_buf;
p->error_buf = &new_error_buf;
} else
saved_error_buf = NULL;
if (!scheme_setjmp(new_error_buf)) {
r = get_tidy_managed(m);
while (!SCHEME_NULLP(r)) {
o = SCHEME_CAR(r);
if (SCHEME_OUTPORTP(o)) {
scheme_flush_if_output_fds(o);
} else {
Scheme_Object *f, *a[1];
f = SCHEME_PTR1_VAL(o);
a[0] = o;
(void)scheme_apply_multi(f, 1, a);
}
r = SCHEME_CDR(r);
}
} else {
escaped = 1;
}
if (catch_errors)
scheme_current_thread->error_buf = saved_error_buf;
return escaped;
}
static Scheme_Object *make_custodian(int argc, Scheme_Object *argv[])
{
Scheme_Custodian *m;
@ -1514,6 +1612,67 @@ static Scheme_Object *custodian_close_all(int argc, Scheme_Object *argv[])
return scheme_void;
}
static Scheme_Object *custodian_tidy_all(int argc, Scheme_Object *argv[])
{
if (!SCHEME_CUSTODIANP(argv[0]))
scheme_wrong_contract("custodian-tidy-all", "custodian?", 0, argc, argv);
scheme_tidy_managed((Scheme_Custodian *)argv[0], 0);
return scheme_void;
}
static Scheme_Object *custodian_add_tidy(int argc, Scheme_Object *argv[])
{
Scheme_Object *e;
Scheme_Custodian_Reference *mref;
Scheme_Custodian *m;
if (!SCHEME_CUSTODIANP(argv[0]))
scheme_wrong_contract("custodian-add-tidy!", "custodian?", 0, argc, argv);
scheme_check_proc_arity("custodian-add-tidy!", 1, 1, argc, argv);
m = (Scheme_Custodian *)argv[0];
if (!scheme_custodian_is_available(m))
scheme_contract_error("custodian-add-tidy!", "the custodian has been shut down",
"custodian", 1, m,
NULL);
e = scheme_alloc_object();
e->type = scheme_custodian_tidy_type;
SCHEME_PTR1_VAL(e) = argv[1];
mref = scheme_add_managed(m, e, NULL, NULL, 1);
SCHEME_PTR2_VAL(e) = mref;
return e;
}
static Scheme_Object *custodian_remove_tidy(int argc, Scheme_Object *argv[])
{
Scheme_Custodian_Reference *mref;
if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_custodian_tidy_type))
scheme_wrong_contract("custodian-remove-tidy!", "custodian-tidy-callback?", 0, argc, argv);
mref = SCHEME_PTR2_VAL(argv[0]);
if (mref) {
SCHEME_PTR2_VAL(argv[0]) = NULL;
scheme_remove_managed(mref, argv[0]);
}
return scheme_void;
}
static Scheme_Object *custodian_tidy_p(int argc, Scheme_Object *argv[])
{
return (SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_custodian_tidy_type)
? scheme_true
: scheme_false);
}
Scheme_Custodian* scheme_custodian_extract_reference(Scheme_Custodian_Reference *mr)
{
return CUSTODIAN_FAM(mr);
@ -1607,7 +1766,7 @@ static Scheme_Object *custodian_to_list(int argc, Scheme_Object *argv[])
o = ex(o);
}
if (o) {
if (o && !SAME_TYPE(SCHEME_TYPE(o), scheme_custodian_tidy_type)) {
hold[j] = o;
j++;
}

View File

@ -227,6 +227,7 @@ scheme_init_type ()
set_name(scheme_custodian_type, "<custodian>");
set_name(scheme_cust_box_type, "<custodian-box>");
set_name(scheme_custodian_tidy_type, "<custodian-tidy-callback>");
set_name(scheme_cont_mark_set_type, "<continuation-mark-set>");
set_name(scheme_cont_mark_chain_type, "<chain>");
@ -726,6 +727,8 @@ void scheme_register_traversers(void)
GC_REG_TRAV(scheme_struct_proc_shape_type, small_atomic_obj);
GC_REG_TRAV(scheme_environment_variables_type, small_object);
GC_REG_TRAV(scheme_custodian_tidy_type, twoptr_obj);
}
END_XFORM_SKIP;