diff options
Diffstat (limited to 'src')
40 files changed, 694 insertions, 244 deletions
diff --git a/src/Makefile b/src/Makefile index 2aa06d4f..496457bb 100644 --- a/src/Makefile +++ b/src/Makefile @@ -245,7 +245,8 @@ BOOT_CMXS := $(BOOT_MLS:.ml=.cmx) BOOT_OBJS := $(BOOT_MLS:.ml=.o) BOOT_CMIS := $(BOOT_MLS:.ml=.cmi) -RUNTIME_CS := rt/sync/spin_lock.cpp \ +RUNTIME_CS := rt/sync/sync.cpp \ + rt/sync/spin_lock.cpp \ rt/sync/lock_free_queue.cpp \ rt/sync/condition_variable.cpp \ rt/rust.cpp \ @@ -279,7 +280,8 @@ RUNTIME_HDR := rt/globals.h \ rt/rust_message.h \ rt/circular_buffer.h \ rt/util/array_list.h \ - rt/util/hash_map.h + rt/util/hash_map.h \ + rt/sync/sync.h RUNTIME_INCS := -Irt/isaac -Irt/uthash RUNTIME_OBJS := $(RUNTIME_CS:.cpp=$(CFG_OBJ_SUFFIX)) @@ -383,7 +385,10 @@ TASK_XFAILS := test/run-pass/acyclic-unwind.rs \ test/run-pass/threads.rs \ test/run-pass/yield.rs +TEST_XFAILS := test/run-pass/arith-0.rs + TEST_XFAILS_X86 := $(TASK_XFAILS) \ + $(TEST_XFAILS) \ test/run-pass/arithmetic-interference.rs \ test/run-pass/bind-obj-ctor.rs \ test/run-pass/child-outlives-parent.rs \ @@ -414,7 +419,9 @@ TEST_XFAILS_X86 := $(TASK_XFAILS) \ test/compile-fail/writing-through-read-alias.rs TEST_XFAILS_LLVM := $(TASK_XFAILS) \ + $(TEST_XFAILS) \ $(addprefix test/run-pass/, \ + arith-1.rs \ acyclic-unwind.rs \ alt-pattern-simple.rs \ alt-tag.rs \ @@ -423,6 +430,8 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \ autoderef-full-lval.rs \ autoderef-objfn.rs \ basic.rs \ + basic-1.rs \ + basic-2.rs \ bind-obj-ctor.rs \ bind-thunk.rs \ bind-trivial.rs \ diff --git a/src/boot/be/abi.ml b/src/boot/be/abi.ml index 347d49fc..5bdf21fa 100644 --- a/src/boot/be/abi.ml +++ b/src/boot/be/abi.ml @@ -41,7 +41,7 @@ let box_gc_header_size = 4;; let box_gc_malloc_return_adjustment = 3;; -let stk_field_valgrind_id = 0 + 1;; +let stk_field_valgrind_id = 0;; let stk_field_limit = stk_field_valgrind_id + 1;; let stk_field_data = stk_field_limit + 1;; @@ -121,7 +121,8 @@ type abi = -> Common.size (* callsz *) -> Common.nabi -> Common.fixup (* grow_task *) - -> unit); + -> bool (* is_obj_fn *) + -> unit); abi_emit_fn_epilogue: (Il.emitter -> unit); diff --git a/src/boot/be/il.ml b/src/boot/be/il.ml index 172d8661..2a5b643a 100644 --- a/src/boot/be/il.ml +++ b/src/boot/be/il.ml @@ -901,6 +901,13 @@ let get_element_ptr (string_of_cell fmt mem_cell) ;; +let ptr_cast (cell:cell) (rty:referent_ty) : cell = + match cell with + Mem (mem, _) -> Mem (mem, rty) + | Reg (reg, AddrTy _) -> Reg (reg, AddrTy rty) + | _ -> bug () "expected address cell in Il.ptr_cast" +;; + (* * Local Variables: * fill-column: 78; diff --git a/src/boot/be/x86.ml b/src/boot/be/x86.ml index 55b101bb..826127a0 100644 --- a/src/boot/be/x86.ml +++ b/src/boot/be/x86.ml @@ -593,6 +593,7 @@ let restore_frame_base (e:Il.emitter) (base:Il.reg) (retpc:Il.reg) : unit = * * *ebp+20+(4*N) = [argN ] * ... + * *ebp+28 = [arg2 ] = obj/closure ptr * *ebp+24 = [arg1 ] = task ptr * *ebp+20 = [arg0 ] = out ptr * *ebp+16 = [retpc ] @@ -1033,7 +1034,7 @@ let unwind_glue (* Puts result in eax; clobbers ecx, edx in the process. *) -let rec calculate_sz (e:Il.emitter) (size:size) : unit = +let rec calculate_sz (e:Il.emitter) (size:size) (in_obj:bool) : unit = let emit = Il.emit e in let mov dst src = emit (Il.umov dst src) in let push x = emit (Il.Push x) in @@ -1045,11 +1046,48 @@ let rec calculate_sz (e:Il.emitter) (size:size) : unit = let mul x y = emit (Il.binary Il.UMUL (rc x) (ro x) (ro y)) in let subi x y = emit (Il.binary Il.SUB (rc x) (ro x) (immi y)) in let eax_gets_a_and_ecx_gets_b a b = - calculate_sz e b; + calculate_sz e b in_obj; push (ro eax); - calculate_sz e a; + calculate_sz e a in_obj; pop (rc ecx); in + + let ty_param_n_in_obj_fn i = + (* + * Here we are trying to immitate the obj-fn branch of + * Trans.get_ty_params_of_current_frame while using + * eax as our only register. + *) + + (* Bind all the referent types we'll need... *) + + let obj_body_rty = Semant.obj_closure_rty word_bits in + let tydesc_rty = Semant.tydesc_rty word_bits in + (* Note that we cheat here and pretend only to have i+1 tydescs (because + we GEP to the i'th while still in this function, so no one outside + finds out about the lie. *) + let tydesc_tys = Array.init (i + 1) (fun _ -> Ast.TY_type) in + let ty_params_ty = Ast.TY_tup tydesc_tys in + let ty_params_rty = Semant.referent_type word_bits ty_params_ty in + + (* ... and fetch! *) + + mov (rc eax) (Il.Cell closure_ptr); + let obj_body = word_n (h eax) Abi.box_rc_field_body in + let obj_body = Il.ptr_cast obj_body obj_body_rty in + let tydesc_ptr = get_element_ptr obj_body Abi.obj_body_elt_tydesc in + + mov (rc eax) (Il.Cell tydesc_ptr); + let tydesc = Il.ptr_cast (word_at (h eax)) tydesc_rty in + let ty_params_ptr = + get_element_ptr tydesc Abi.tydesc_field_first_param + in + + mov (rc eax) (Il.Cell ty_params_ptr); + let ty_params = Il.ptr_cast (word_at (h eax)) ty_params_rty in + get_element_ptr ty_params i + in + match size with SIZE_fixed i -> mov (rc eax) (immi i) @@ -1061,15 +1099,23 @@ let rec calculate_sz (e:Il.emitter) (size:size) : unit = mov (rc eax) (imm (Asm.M_POS f)) | SIZE_param_size i -> - mov (rc eax) (Il.Cell (ty_param_n i)); + if in_obj + then + mov (rc eax) (Il.Cell (ty_param_n_in_obj_fn i)) + else + mov (rc eax) (Il.Cell (ty_param_n i)); mov (rc eax) (Il.Cell (word_n (h eax) Abi.tydesc_field_size)) | SIZE_param_align i -> - mov (rc eax) (Il.Cell (ty_param_n i)); + if in_obj + then + mov (rc eax) (Il.Cell (ty_param_n_in_obj_fn i)) + else + mov (rc eax) (Il.Cell (ty_param_n i)); mov (rc eax) (Il.Cell (word_n (h eax) Abi.tydesc_field_align)) | SIZE_rt_neg a -> - calculate_sz e a; + calculate_sz e a in_obj; neg eax | SIZE_rt_add (a, b) -> @@ -1185,6 +1231,7 @@ let fn_prologue (callsz:size) (nabi:nabi) (grow_task_fixup:fixup) + (is_obj_fn:bool) : unit = let esi_n = word_n (h esi) in @@ -1314,7 +1361,7 @@ let fn_prologue emit (Il.jmp Il.JA Il.CodeNone); (* Calculate dynamic frame size. *) - calculate_sz e call_and_frame_sz; + calculate_sz e call_and_frame_sz is_obj_fn; ((ro eax), Some primordial_underflow_jmp_pc) end | Some e -> ((imm e), None) diff --git a/src/boot/me/dwarf.ml b/src/boot/me/dwarf.ml index d3fb81de..0ec7af78 100644 --- a/src/boot/me/dwarf.ml +++ b/src/boot/me/dwarf.ml @@ -1677,7 +1677,7 @@ let dwarf_visitor in let record trec = - let rty = referent_type abi (Ast.TY_rec trec) in + let rty = referent_type word_bits (Ast.TY_rec trec) in let rty_sz = Il.referent_ty_size abi.Abi.abi_word_bits in let fix = new_fixup "record type DIE" in let die = DEF (fix, SEQ [| @@ -1926,7 +1926,7 @@ let dwarf_visitor * I'm a bit surprised by that! *) - let rty = referent_type abi (Ast.TY_tag ttag) in + let rty = referent_type word_bits (Ast.TY_tag ttag) in let rty_sz = Il.referent_ty_size abi.Abi.abi_word_bits in let rtys = match rty with diff --git a/src/boot/me/layout.ml b/src/boot/me/layout.ml index 1df37f0f..cfd087ff 100644 --- a/src/boot/me/layout.ml +++ b/src/boot/me/layout.ml @@ -113,7 +113,7 @@ let layout_visitor | Il.CodeTy -> true | Il.NilTy -> false in - rt_in_mem (slot_referent_type cx.ctxt_abi slot) + rt_in_mem (slot_referent_type cx.ctxt_abi.Abi.abi_word_bits slot) in let rty_sz rty = Il.referent_ty_size cx.ctxt_abi.Abi.abi_word_bits rty in @@ -142,7 +142,7 @@ let layout_visitor : unit = let accum (off,align) id : (size * size) = let slot = get_slot cx id in - let rt = slot_referent_type cx.ctxt_abi slot in + let rt = slot_referent_type cx.ctxt_abi.Abi.abi_word_bits slot in let (elt_size, elt_align) = rty_layout rt in if vregs_ok && (is_subword_size elt_size) @@ -170,7 +170,9 @@ let layout_visitor then elt_off else neg_sz (add_sz elt_off elt_size) in - Stack.push (slot_referent_type cx.ctxt_abi slot) slot_accum; + Stack.push + (slot_referent_type cx.ctxt_abi.Abi.abi_word_bits slot) + slot_accum; iflog begin fun _ -> diff --git a/src/boot/me/semant.ml b/src/boot/me/semant.ml index bcaec2b4..a3a8abdf 100644 --- a/src/boot/me/semant.ml +++ b/src/boot/me/semant.ml @@ -1822,24 +1822,24 @@ let run_passes (* Rust type -> IL type conversion. *) -let word_sty (abi:Abi.abi) : Il.scalar_ty = - Il.ValTy abi.Abi.abi_word_bits +let word_sty (word_bits:Il.bits) : Il.scalar_ty = + Il.ValTy word_bits ;; -let word_rty (abi:Abi.abi) : Il.referent_ty = - Il.ScalarTy (word_sty abi) +let word_rty (word_bits:Il.bits) : Il.referent_ty = + Il.ScalarTy (word_sty word_bits) ;; -let tydesc_rty (abi:Abi.abi) : Il.referent_ty = +let tydesc_rty (word_bits:Il.bits) : Il.referent_ty = (* * NB: must match corresponding tydesc structure * in trans and offsets in ABI exactly. *) Il.StructTy [| - word_rty abi; (* Abi.tydesc_field_first_param *) - word_rty abi; (* Abi.tydesc_field_size *) - word_rty abi; (* Abi.tydesc_field_align *) + word_rty word_bits; (* Abi.tydesc_field_first_param *) + word_rty word_bits; (* Abi.tydesc_field_size *) + word_rty word_bits; (* Abi.tydesc_field_align *) Il.ScalarTy (Il.AddrTy Il.CodeTy); (* Abi.tydesc_field_copy_glue *) Il.ScalarTy (Il.AddrTy Il.CodeTy); (* Abi.tydesc_field_drop_glue *) Il.ScalarTy (Il.AddrTy Il.CodeTy); (* Abi.tydesc_field_free_glue *) @@ -1849,29 +1849,29 @@ let tydesc_rty (abi:Abi.abi) : Il.referent_ty = |] ;; -let obj_closure_rty (abi:Abi.abi) : Il.referent_ty = +let obj_closure_rty (word_bits:Il.bits) : Il.referent_ty = Il.StructTy [| - word_rty abi; + word_rty word_bits; Il.StructTy [| - Il.ScalarTy (Il.AddrTy (tydesc_rty abi)); - word_rty abi (* A lie: it's opaque, but this permits - * GEP'ing to it. *) + Il.ScalarTy (Il.AddrTy (tydesc_rty word_bits)); + word_rty word_bits (* A lie: it's opaque, but this permits + * GEP'ing to it. *) |] |] ;; -let rec referent_type (abi:Abi.abi) (t:Ast.ty) : Il.referent_ty = +let rec referent_type (word_bits:Il.bits) (t:Ast.ty) : Il.referent_ty = let s t = Il.ScalarTy t in let v b = Il.ValTy b in let p t = Il.AddrTy t in let sv b = s (v b) in let sp t = s (p t) in - let word = word_rty abi in + let word = word_rty word_bits in let ptr = sp Il.OpaqueTy in let rc_ptr = sp (Il.StructTy [| word; Il.OpaqueTy |]) in let codeptr = sp Il.CodeTy in - let tup ttup = Il.StructTy (Array.map (referent_type abi) ttup) in + let tup ttup = Il.StructTy (Array.map (referent_type word_bits) ttup) in let tag ttag = let union = Il.UnionTy @@ -1916,7 +1916,7 @@ let rec referent_type (abi:Abi.abi) (t:Ast.ty) : Il.referent_ty = Il.StructTy [| codeptr; fn_closure_ptr |] | Ast.TY_obj _ -> - let obj_closure_ptr = sp (obj_closure_rty abi) in + let obj_closure_ptr = sp (obj_closure_rty word_bits) in Il.StructTy [| ptr; obj_closure_ptr |] | Ast.TY_tag ttag -> tag ttag @@ -1928,26 +1928,26 @@ let rec referent_type (abi:Abi.abi) (t:Ast.ty) : Il.referent_ty = | Ast.TY_port _ | Ast.TY_task -> rc_ptr - | Ast.TY_type -> sp (tydesc_rty abi) + | Ast.TY_type -> sp (tydesc_rty word_bits) | Ast.TY_native _ -> ptr | Ast.TY_box t -> - sp (Il.StructTy [| word; referent_type abi t |]) + sp (Il.StructTy [| word; referent_type word_bits t |]) - | Ast.TY_mutable t -> referent_type abi t + | Ast.TY_mutable t -> referent_type word_bits t | Ast.TY_param (i, _) -> Il.ParamTy i | Ast.TY_named _ -> bug () "named type in referent_type" - | Ast.TY_constrained (t, _) -> referent_type abi t + | Ast.TY_constrained (t, _) -> referent_type word_bits t -and slot_referent_type (abi:Abi.abi) (sl:Ast.slot) : Il.referent_ty = +and slot_referent_type (word_bits:Il.bits) (sl:Ast.slot) : Il.referent_ty = let s t = Il.ScalarTy t in let p t = Il.AddrTy t in let sp t = s (p t) in - let rty = referent_type abi (slot_ty sl) in + let rty = referent_type word_bits (slot_ty sl) in match sl.Ast.slot_mode with | Ast.MODE_local -> rty | Ast.MODE_alias -> sp rty @@ -1958,7 +1958,7 @@ let task_rty (abi:Abi.abi) : Il.referent_ty = begin Array.init Abi.n_visible_task_fields - (fun _ -> word_rty abi) + (fun _ -> word_rty abi.Abi.abi_word_bits) end ;; @@ -1970,14 +1970,17 @@ let call_args_referent_type_full (iterator_arg_rtys:Il.referent_ty array) (indirect_arg_rtys:Il.referent_ty array) : Il.referent_ty = - let out_slot_rty = slot_referent_type abi out_slot in + let out_slot_rty = slot_referent_type abi.Abi.abi_word_bits out_slot in let out_ptr_rty = Il.ScalarTy (Il.AddrTy out_slot_rty) in let task_ptr_rty = Il.ScalarTy (Il.AddrTy (task_rty abi)) in let ty_param_rtys = - let td = Il.ScalarTy (Il.AddrTy (tydesc_rty abi)) in + let td = Il.ScalarTy (Il.AddrTy (tydesc_rty abi.Abi.abi_word_bits)) in Il.StructTy (Array.init n_ty_params (fun _ -> td)) in - let arg_rtys = Il.StructTy (Array.map (slot_referent_type abi) in_slots) in + let arg_rtys = + Il.StructTy + (Array.map (slot_referent_type abi.Abi.abi_word_bits) in_slots) + in (* * NB: must match corresponding calltup structure in trans and * member indices in ABI exactly. @@ -2003,7 +2006,7 @@ let call_args_referent_type (* Abi.indirect_args_elt_closure *) match closure with None -> - [| word_rty cx.ctxt_abi |] + [| word_rty cx.ctxt_abi.Abi.abi_word_bits |] | Some c -> [| Il.ScalarTy (Il.AddrTy c) |] in @@ -2057,16 +2060,18 @@ let direct_call_args_referent_type ;; let ty_sz (abi:Abi.abi) (t:Ast.ty) : int64 = - force_sz (Il.referent_ty_size abi.Abi.abi_word_bits (referent_type abi t)) + let wb = abi.Abi.abi_word_bits in + force_sz (Il.referent_ty_size wb (referent_type wb t)) ;; let ty_align (abi:Abi.abi) (t:Ast.ty) : int64 = - force_sz (Il.referent_ty_align abi.Abi.abi_word_bits (referent_type abi t)) + let wb = abi.Abi.abi_word_bits in + force_sz (Il.referent_ty_align wb (referent_type wb t)) ;; let slot_sz (abi:Abi.abi) (s:Ast.slot) : int64 = - force_sz (Il.referent_ty_size abi.Abi.abi_word_bits - (slot_referent_type abi s)) + let wb = abi.Abi.abi_word_bits in + force_sz (Il.referent_ty_size wb (slot_referent_type wb s)) ;; let word_slot (abi:Abi.abi) : Ast.slot = diff --git a/src/boot/me/trans.ml b/src/boot/me/trans.ml index 01a89c56..620b27e7 100644 --- a/src/boot/me/trans.ml +++ b/src/boot/me/trans.ml @@ -292,7 +292,7 @@ let trans_visitor in let ptr_at (mem:Il.mem) (pointee_ty:Ast.ty) : Il.cell = - rty_ptr_at mem (referent_type abi pointee_ty) + rty_ptr_at mem (referent_type word_bits pointee_ty) in let need_scalar_ty (rty:Il.referent_ty) : Il.scalar_ty = @@ -330,11 +330,7 @@ let trans_visitor (cell_str mem_cell) in - let rec ptr_cast (cell:Il.cell) (rty:Il.referent_ty) : Il.cell = - match cell with - Il.Mem (mem, _) -> Il.Mem (mem, rty) - | Il.Reg (reg, Il.AddrTy _) -> Il.Reg (reg, Il.AddrTy rty) - | _ -> bug () "expected address cell in Trans.ptr_cast" + let rec ptr_cast = Il.ptr_cast and curr_crate_ptr _ : Il.cell = word_at (fp_imm frame_crate_ptr) @@ -453,13 +449,22 @@ let trans_visitor in let slot_id_referent_type (slot_id:node_id) : Il.referent_ty = - slot_referent_type abi (get_slot cx slot_id) + slot_referent_type word_bits (get_slot cx slot_id) in let caller_args_cell (args_rty:Il.referent_ty) : Il.cell = Il.Mem (fp_imm out_mem_disp, args_rty) in + let get_obj_box_from_calltup (args_cell:Il.cell) = + let indirect_args = + get_element_ptr args_cell Abi.calltup_elt_indirect_args + in + deref (ptr_cast + (get_element_ptr indirect_args Abi.indirect_args_elt_closure) + (Il.ScalarTy (Il.AddrTy (obj_closure_rty word_bits)))) + in + let fp_to_args (fp:Il.cell) (args_rty:Il.referent_ty): Il.cell = let (reg, _) = force_to_reg (Il.Cell fp) in Il.Mem(based_imm reg out_mem_disp, args_rty) @@ -469,11 +474,43 @@ let trans_visitor get_element_ptr ty_params param_idx in - let get_ty_params_of_frame (fp:Il.reg) (n_params:int) : Il.cell = - let fn_ty = mk_simple_ty_fn [| |] in - let fn_rty = call_args_referent_type cx n_params fn_ty None in - let args_cell = Il.Mem (based_imm fp out_mem_disp, fn_rty) in - get_element_ptr args_cell Abi.calltup_elt_ty_params + let get_ty_params_of_frame + (fnid:node_id) + (fp:Il.reg) + (n_ty_params:int) + : Il.cell = + + let fn_ty = mk_simple_ty_fn [| |] in + let fn_rty = + call_args_referent_type cx n_ty_params fn_ty (Some Il.OpaqueTy) + in + let args_cell = Il.Mem (based_imm fp out_mem_disp, fn_rty) in + + if defn_id_is_obj_fn_or_drop cx fnid + then + (* + * To get the typarams in an obj fn, we must go to the + * implicit obj's captured type descriptor. + *) + let obj_box = + get_obj_box_from_calltup args_cell + in + let obj = get_element_ptr obj_box Abi.box_rc_field_body in + let tydesc = get_element_ptr obj Abi.obj_body_elt_tydesc in + let ty_params_ty = Ast.TY_tup (make_tydesc_tys n_ty_params) in + let ty_params_rty = referent_type word_bits ty_params_ty in + let ty_params = + get_element_ptr (deref tydesc) Abi.tydesc_field_first_param + in + let ty_params = + ptr_cast ty_params (Il.ScalarTy (Il.AddrTy ty_params_rty)) + in + deref ty_params + else + (* + * Regular function --- typarams are right in the frame calltup. + *) + get_element_ptr args_cell Abi.calltup_elt_ty_params in let get_args_for_current_frame _ = @@ -520,34 +557,10 @@ let trans_visitor Abi.iterator_args_elt_outer_frame_ptr in - let get_obj_for_current_frame _ = - deref (ptr_cast - (get_closure_for_current_frame ()) - (Il.ScalarTy (Il.AddrTy (obj_closure_rty abi)))) - in - let get_ty_params_of_current_frame _ : Il.cell = - let id = current_fn() in - let n_ty_params = n_item_ty_params cx id in - if defn_id_is_obj_fn_or_drop cx id - then - begin - let obj_box = get_obj_for_current_frame() in - let obj = get_element_ptr obj_box Abi.box_rc_field_body in - let tydesc = get_element_ptr obj Abi.obj_body_elt_tydesc in - let ty_params_ty = Ast.TY_tup (make_tydesc_tys n_ty_params) in - let ty_params_rty = referent_type abi ty_params_ty in - let ty_params = - get_element_ptr (deref tydesc) Abi.tydesc_field_first_param - in - let ty_params = - ptr_cast ty_params (Il.ScalarTy (Il.AddrTy ty_params_rty)) - in - deref ty_params - end - - else - get_ty_params_of_frame abi.Abi.abi_fp_reg n_ty_params + let fnid = current_fn() in + let n_ty_params = n_item_ty_params cx fnid in + get_ty_params_of_frame fnid abi.Abi.abi_fp_reg n_ty_params in let get_ty_param_in_current_frame (param_idx:int) : Il.cell = @@ -721,7 +734,7 @@ let trans_visitor in let ty_sz_in_current_frame (ty:Ast.ty) : Il.operand = - let rty = referent_type abi ty in + let rty = referent_type word_bits ty in let sz = Il.referent_ty_size word_bits rty in calculate_sz_in_current_frame sz in @@ -730,7 +743,7 @@ let trans_visitor (ty_params:Il.cell) (ty:Ast.ty) : Il.operand = - let rty = referent_type abi ty in + let rty = referent_type word_bits ty in let sz = Il.referent_ty_size word_bits rty in calculate_sz ty_params sz in @@ -931,7 +944,7 @@ let trans_visitor mov idx atop; emit (Il.binary Il.UMUL idx (Il.Cell idx) unit_sz); let elt_mem = trans_bounds_check (deref cell) (Il.Cell idx) in - (Il.Mem (elt_mem, referent_type abi ty), ty) + (Il.Mem (elt_mem, referent_type word_bits ty), ty) in (* * All lval components aside from explicit-deref just auto-deref @@ -1120,7 +1133,7 @@ let trans_visitor and trans_static_string (s:string) : Il.operand = Il.Cell (crate_rel_to_ptr (trans_crate_rel_static_string_operand s) - (referent_type abi Ast.TY_str)) + (referent_type word_bits Ast.TY_str)) and get_static_tydesc (idopt:node_id option) @@ -1226,7 +1239,7 @@ let trans_visitor let fty = Hashtbl.find (snd caller) ident in let self_args_rty = call_args_referent_type cx 0 - (Ast.TY_fn fty) (Some (obj_closure_rty abi)) + (Ast.TY_fn fty) (Some (obj_closure_rty word_bits)) in let callsz = Il.referent_ty_size word_bits self_args_rty in let spill = new_fixup "forwarding fn spill" in @@ -1394,7 +1407,7 @@ let trans_visitor push_new_emitter_with_vregs None; iflog (fun _ -> annotate "prologue"); abi.Abi.abi_emit_fn_prologue (emitter()) - framesz callsz nabi_rust (upcall_fixup "upcall_grow_task"); + framesz callsz nabi_rust (upcall_fixup "upcall_grow_task") false; write_frame_info_ptrs None; (* FIXME: not clear why, but checking interrupt in glue context * causes many.rs to crash when run on a sufficiently large number @@ -1473,8 +1486,8 @@ let trans_visitor (* FIXME (issue #5): mutability flag *) : Il.referent_ty = let rc = Il.ScalarTy word_sty in - let targ = referent_type abi (mk_simple_ty_fn [||]) in - let bindings = Array.map (slot_referent_type abi) bs in + let targ = referent_type word_bits (mk_simple_ty_fn [||]) in + let bindings = Array.map (slot_referent_type word_bits) bs in Il.StructTy [| rc; targ; Il.StructTy bindings |] (* FIXME (issue #2): this should eventually use tail calling logic *) @@ -2333,7 +2346,7 @@ let trans_visitor (get_element_ptr_dyn_in_current_frame vec Abi.vec_elt_data)) in - let unit_rty = referent_type abi unit_ty in + let unit_rty = referent_type word_bits unit_ty in let body_rty = Il.StructTy (Array.map (fun _ -> unit_rty) atoms) in let body = Il.Mem (body_mem, body_rty) in Array.iteri @@ -2379,12 +2392,12 @@ let trans_visitor let root_desc = Il.Cell (crate_rel_to_ptr (get_static_tydesc idopt t 0L 0L force_stateful) - (tydesc_rty abi)) + (tydesc_rty word_bits)) in let (t, param_descs) = linearize_ty_params t in let descs = Array.append [| root_desc |] param_descs in let n = Array.length descs in - let rty = referent_type abi t in + let rty = referent_type word_bits t in let (size_sz, align_sz) = Il.referent_ty_layout word_bits rty in let size = calculate_sz_in_current_frame size_sz in let align = calculate_sz_in_current_frame align_sz in @@ -2420,7 +2433,7 @@ let trans_visitor (ty_sz abi ty) (ty_align abi ty) mut) - (tydesc_rty abi)) + (tydesc_rty word_bits)) and box_rc_cell (cell:Il.cell) : Il.cell = get_element_ptr (deref cell) Abi.box_rc_field_refcnt @@ -2437,7 +2450,7 @@ let trans_visitor in let ty = simplified_ty ty in let refty_sz = - Il.referent_ty_size abi.Abi.abi_word_bits (referent_type abi ty) + Il.referent_ty_size abi.Abi.abi_word_bits (referent_type word_bits ty) in match refty_sz with SIZE_fixed _ -> imm (Int64.add (ty_sz abi ty) header_sz) @@ -2534,7 +2547,7 @@ let trans_visitor trans_compare_simple Il.JAE (Il.Cell ptr) (Il.Cell lim) in let unit_cell = - deref (ptr_cast ptr (referent_type abi unit_ty)) + deref (ptr_cast ptr (referent_type word_bits unit_ty)) in f unit_cell unit_cell unit_ty curr_iso; add_to ptr unit_sz; @@ -2934,6 +2947,7 @@ let trans_visitor (slot:Ast.slot) (curr_iso:Ast.ty_iso option) : unit = + check_and_flush_chan cell slot; drop_slot (get_ty_params_of_current_frame()) cell slot curr_iso and drop_ty_in_current_frame @@ -4190,6 +4204,25 @@ let trans_visitor let last_jumps = Array.map trans_arm at.Ast.alt_tag_arms in Array.iter patch last_jumps + (* If we're about to drop a channel, synthesize an upcall_flush_chan. + * TODO: This should rather appear in a chan dtor when chans become + * objects. *) + and check_and_flush_chan + (cell:Il.cell) + (slot:Ast.slot) + : unit = + let ty = strip_mutable_or_constrained_ty (slot_ty slot) in + match simplified_ty ty with + Ast.TY_chan _ -> + annotate "check_and_flush_chan, flush_chan"; + let rc = box_rc_cell cell in + emit (Il.cmp (Il.Cell rc) one); + let jump = mark () in + emit (Il.jmp Il.JNE Il.CodeNone); + trans_void_upcall "upcall_flush_chan" [| Il.Cell cell |]; + patch jump; + | _ -> () + and drop_slots_at_curr_stmt _ : unit = let stmt = Stack.top curr_stmt in match htab_search cx.ctxt_post_stmt_slot_drops stmt with @@ -4292,7 +4325,7 @@ let trans_visitor push_new_emitter_with_vregs (Some id); iflog (fun _ -> annotate "prologue"); abi.Abi.abi_emit_fn_prologue (emitter()) - framesz callsz nabi_rust (upcall_fixup "upcall_grow_task"); + framesz callsz nabi_rust (upcall_fixup "upcall_grow_task") false; write_frame_info_ptrs None; iflog (fun _ -> annotate "finished prologue"); trans_block fe.Ast.for_each_body; @@ -4376,7 +4409,7 @@ let trans_visitor let dst_fill = get_element_ptr dst_vec Abi.vec_elt_fill in (* Copy loop: *) - let eltp_rty = Il.AddrTy (referent_type abi elt_ty) in + let eltp_rty = Il.AddrTy (referent_type word_bits elt_ty) in let dptr = next_vreg_cell eltp_rty in let sptr = next_vreg_cell eltp_rty in let dlim = next_vreg_cell eltp_rty in @@ -4696,6 +4729,8 @@ let trans_visitor let get_frame_glue glue inner = get_mem_glue glue begin + (* `mem` here is a pointer to the frame we are marking, dropping, + or relocing, etc. *) fun mem -> iter_frame_and_arg_slots cx fnid begin @@ -4703,10 +4738,19 @@ let trans_visitor match htab_search cx.ctxt_slot_offsets slot_id with Some off when not (slot_is_obj_state cx slot_id) -> let referent_type = slot_id_referent_type slot_id in + (* + * This might look as though we're always taking the + * pointer-to-frame and giving it the type of the + * frame/arg of interest, but this is because our + * deref_off a few lines later takes the referent + * type of the given poiinter (`st`) as the referent + * type of the mem-offset-from-the-given-pointer + * that it returns. + *) let fp_cell = rty_ptr_at mem referent_type in let (fp, st) = force_to_reg (Il.Cell fp_cell) in let ty_params = - get_ty_params_of_frame fp n_ty_params + get_ty_params_of_frame fnid fp n_ty_params in let slot_cell = deref_off_sz ty_params (Il.Reg (fp,st)) off @@ -4754,7 +4798,7 @@ let trans_visitor end in - let trans_frame_entry (fnid:node_id) : unit = + let trans_frame_entry (fnid:node_id) (obj_fn:bool) : unit = let framesz = get_framesz cx fnid in let callsz = get_callsz cx fnid in Stack.push (Stack.create()) epilogue_jumps; @@ -4768,7 +4812,7 @@ let trans_visitor (string_of_size callsz))); abi.Abi.abi_emit_fn_prologue (emitter()) framesz callsz nabi_rust - (upcall_fixup "upcall_grow_task"); + (upcall_fixup "upcall_grow_task") obj_fn; write_frame_info_ptrs (Some fnid); check_interrupt_flag (); @@ -4792,8 +4836,9 @@ let trans_visitor let trans_fn (fnid:node_id) (body:Ast.block) + (obj_fn:bool) : unit = - trans_frame_entry fnid; + trans_frame_entry fnid obj_fn; trans_block body; trans_frame_exit fnid true; in @@ -4802,7 +4847,7 @@ let trans_visitor (obj_id:node_id) (header:Ast.header_slots) : unit = - trans_frame_entry obj_id; + trans_frame_entry obj_id true; let all_args_rty = current_fn_args_rty None in let all_args_cell = caller_args_cell all_args_rty in @@ -4821,7 +4866,7 @@ let trans_visitor let obj_args_ty = Ast.TY_tup obj_args_tup in let state_ty = Ast.TY_tup [| Ast.TY_type; obj_args_ty |] in let state_ptr_ty = Ast.TY_box state_ty in - let state_ptr_rty = referent_type abi state_ptr_ty in + let state_ptr_rty = referent_type word_bits state_ptr_ty in let state_malloc_sz = box_allocation_size state_ptr_ty in let ctor_ty = Hashtbl.find cx.ctxt_all_item_types obj_id in @@ -4923,7 +4968,7 @@ let trans_visitor in let trans_required_fn (fnid:node_id) (blockid:node_id) : unit = - trans_frame_entry fnid; + trans_frame_entry fnid false; emit (Il.Enter (Hashtbl.find cx.ctxt_block_fixups blockid)); let (ilib, conv) = Hashtbl.find cx.ctxt_required_items fnid in let lib_num = @@ -5061,7 +5106,7 @@ let trans_visitor (tagid:node_id) (tag:(Ast.header_tup * Ast.ty_tag * node_id)) : unit = - trans_frame_entry tagid; + trans_frame_entry tagid false; trace_str cx.ctxt_sess.Session.sess_trace_tag ("in tag constructor " ^ n); let (header_tup, _, _) = tag in @@ -5124,7 +5169,7 @@ let trans_visitor iflog (fun _ -> log cx "translating defined item #%d = %s" (int_of_node i.id) (path_name())); match i.node.Ast.decl_item with - Ast.MOD_ITEM_fn f -> trans_fn i.id f.Ast.fn_body + Ast.MOD_ITEM_fn f -> trans_fn i.id f.Ast.fn_body false | Ast.MOD_ITEM_tag t -> trans_tag n i.id t | Ast.MOD_ITEM_obj ob -> trans_obj_ctor i.id @@ -5158,7 +5203,7 @@ let trans_visitor push_new_emitter_with_vregs (Some b.id); iflog (fun _ -> annotate "prologue"); abi.Abi.abi_emit_fn_prologue (emitter()) - framesz callsz nabi_rust (upcall_fixup "upcall_grow_task"); + framesz callsz nabi_rust (upcall_fixup "upcall_grow_task") true; write_frame_info_ptrs None; iflog (fun _ -> annotate "finished prologue"); trans_block b; @@ -5168,7 +5213,7 @@ let trans_visitor in let visit_defined_obj_fn_pre _ _ fn = - trans_fn fn.id fn.node.Ast.fn_body + trans_fn fn.id fn.node.Ast.fn_body true in let visit_required_obj_fn_pre _ _ _ = diff --git a/src/lib/deque.rs b/src/lib/deque.rs index bf7acb53..3f2a81a4 100644 --- a/src/lib/deque.rs +++ b/src/lib/deque.rs @@ -47,7 +47,7 @@ fn create[T]() -> t[T] { ret _vec.init_fn[cell[T]](copy_op, nalloc); } - fn get[T](&vec[cell[T]] elts, uint i) -> T { + fn get[T](vec[cell[T]] elts, uint i) -> T { alt (elts.(i)) { case (util.some[T](t)) { ret t; } case (_) { fail; } @@ -100,6 +100,7 @@ fn create[T]() -> t[T] { let T t = get[T](elts, lo); elts.(lo) = util.none[T](); lo = (lo + 1u) % _vec.len[cell[T]](elts); + nelts -= 1u; ret t; } @@ -112,6 +113,7 @@ fn create[T]() -> t[T] { let T t = get[T](elts, hi); elts.(hi) = util.none[T](); + nelts -= 1u; ret t; } diff --git a/src/rt/circular_buffer.cpp b/src/rt/circular_buffer.cpp index a93f2572..dbf5059b 100644 --- a/src/rt/circular_buffer.cpp +++ b/src/rt/circular_buffer.cpp @@ -31,9 +31,7 @@ circular_buffer::circular_buffer(rust_dom *dom, size_t unit_sz) : } circular_buffer::~circular_buffer() { - dom->log(rust_log::MEM | rust_log::COMM, - "~circular_buffer 0x%" PRIxPTR, - this); + dom->log(rust_log::MEM, "~circular_buffer 0x%" PRIxPTR, this); I(dom, _buffer); W(dom, _unread == 0, "~circular_buffer with unread messages."); dom->free(_buffer); diff --git a/src/rt/globals.h b/src/rt/globals.h index f8025a40..85aa5860 100644 --- a/src/rt/globals.h +++ b/src/rt/globals.h @@ -20,12 +20,14 @@ extern "C" { } #elif defined(__GNUC__) #include <unistd.h> +#include <sys/time.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <dlfcn.h> #include <pthread.h> #include <errno.h> +#include <time.h> #else #error "Platform not supported." #endif diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp index 82a19cbc..d0215edc 100644 --- a/src/rt/rust.cpp +++ b/src/rt/rust.cpp @@ -53,7 +53,9 @@ rust_srv::realloc(void *p, size_t bytes) } void * val = ::realloc(p, bytes); #ifdef TRACK_ALLOCATIONS - if (allocation_list.replace(p, val) == NULL) { + if (allocation_list.replace(p, val) == false) { + printf("realloc: ptr 0x%" PRIxPTR " is not in allocation_list\n", + (uintptr_t) p); fatal("not in allocation_list", __FILE__, __LINE__); } #endif @@ -64,8 +66,8 @@ void rust_srv::free(void *p) { #ifdef TRACK_ALLOCATIONS - if (allocation_list.replace(p, NULL) == NULL) { - printf("ptr 0x%" PRIxPTR " is not in allocation_list\n", + if (allocation_list.replace(p, NULL) == false) { + printf("free: ptr 0x%" PRIxPTR " is not in allocation_list\n", (uintptr_t) p); fatal("not in allocation_list", __FILE__, __LINE__); } diff --git a/src/rt/rust_chan.cpp b/src/rt/rust_chan.cpp index f107d287..2a0a61db 100644 --- a/src/rt/rust_chan.cpp +++ b/src/rt/rust_chan.cpp @@ -18,9 +18,11 @@ rust_chan::rust_chan(rust_task *task, maybe_proxy<rust_port> *port) : } rust_chan::~rust_chan() { - if (port && !port->is_proxy()) { - port->delegate()->chans.swap_delete(this); - } + task->log(rust_log::MEM | rust_log::COMM, + "del rust_chan(task=0x%" PRIxPTR ")", (uintptr_t) this); + + A(task->dom, is_associated() == false, + "Channel must be disassociated before being freed."); } /** @@ -28,7 +30,10 @@ rust_chan::~rust_chan() { */ void rust_chan::associate(maybe_proxy<rust_port> *port) { this->port = port; - if (!port->is_proxy()) { + if (port->is_proxy() == false) { + task->log(rust_log::TASK, + "associating chan: 0x%" PRIxPTR " with port: 0x%" PRIxPTR, + this, port); this->port->delegate()->chans.push(this); } } @@ -43,14 +48,23 @@ bool rust_chan::is_associated() { void rust_chan::disassociate() { A(task->dom, is_associated(), "Channel must be associated with a port."); + if (port->is_proxy() == false) { + task->log(rust_log::TASK, + "disassociating chan: 0x%" PRIxPTR " from port: 0x%" PRIxPTR, + this, port->delegate()); + port->delegate()->chans.swap_delete(this); + } + // Delete reference to the port. port = NULL; } /** - * Attempt to transmit channel data to the associated port. + * Attempt to send data to the associated port. */ -void rust_chan::transmit() { +void rust_chan::send(void *sptr) { + buffer.enqueue(sptr); + rust_dom *dom = task->dom; if (!is_associated()) { W(dom, is_associated(), @@ -81,7 +95,6 @@ void rust_chan::transmit() { return; } - // // Local Variables: // mode: C++ diff --git a/src/rt/rust_chan.h b/src/rt/rust_chan.h index 055e359a..6aa98247 100644 --- a/src/rt/rust_chan.h +++ b/src/rt/rust_chan.h @@ -17,7 +17,7 @@ public: void disassociate(); bool is_associated(); - void transmit(); + void send(void *sptr); }; // diff --git a/src/rt/rust_dom.cpp b/src/rt/rust_dom.cpp index 004a1027..f7b8e97b 100644 --- a/src/rt/rust_dom.cpp +++ b/src/rt/rust_dom.cpp @@ -4,6 +4,8 @@ template class ptr_vec<rust_task>; +// Keeps track of all live domains, for debugging purposes. +array_list<rust_dom*> _live_domains; rust_dom::rust_dom(rust_srv *srv, rust_crate const *root_crate, const char *name) : @@ -28,13 +30,18 @@ rust_dom::rust_dom(rust_srv *srv, rust_crate const *root_crate, pthread_attr_setdetachstate(&attr, true); #endif root_task = new (this) rust_task(this, NULL, name); + + if (_live_domains.replace(NULL, this) == false) { + _live_domains.append(this); + } } static void del_all_tasks(rust_dom *dom, ptr_vec<rust_task> *v) { I(dom, v); while (v->length()) { - dom->log(rust_log::TASK, "deleting task %" PRIdPTR, v->length() - 1); + dom->log(rust_log::TASK, "deleting task 0x%" PRIdPTR, + v->length() - 1); delete v->pop(); } } @@ -45,7 +52,7 @@ rust_dom::delete_proxies() { rust_proxy<rust_task> *task_proxy; while (_task_proxies.pop(&task, &task_proxy)) { log(rust_log::TASK, - "deleting proxy %" PRIxPTR " in dom %s @0x%" PRIxPTR, + "deleting proxy 0x%" PRIxPTR " in dom %s 0x%" PRIxPTR, task_proxy, task_proxy->dom->name, task_proxy->dom); delete task_proxy; } @@ -54,7 +61,7 @@ rust_dom::delete_proxies() { rust_proxy<rust_port> *port_proxy; while (_port_proxies.pop(&port, &port_proxy)) { log(rust_log::TASK, - "deleting proxy %" PRIxPTR " in dom %s @0x%" PRIxPTR, + "deleting proxy 0x%" PRIxPTR " in dom %s 0x%" PRIxPTR, port_proxy, port_proxy->dom->name, port_proxy->dom); delete port_proxy; } @@ -77,6 +84,8 @@ rust_dom::~rust_dom() { #endif while (caches.length()) delete caches.pop(); + + _live_domains.replace(this, NULL); } void @@ -232,7 +241,6 @@ rust_dom::reap_dead_tasks() { rust_task *task = dead_tasks[i]; if (task->ref_count == 0) { I(this, task->tasks_waiting_to_join.is_empty()); - dead_tasks.swap_delete(task); log(rust_log::TASK, "deleting unreferenced dead task %s @0x%" PRIxPTR, @@ -250,14 +258,14 @@ rust_dom::reap_dead_tasks() { */ void rust_dom::send_message(rust_message *message) { log(rust_log::COMM, "==> enqueueing \"%s\" 0x%" PRIxPTR - " in queue 0x%" PRIxPTR, + " in queue 0x%" PRIxPTR + " in domain 0x%" PRIxPTR, message->label, message, - &_incoming_message_queue); + &_incoming_message_queue, + this); A(this, message->dom == this, "Message owned by non-local domain."); _incoming_message_queue.enqueue(message); - _incoming_message_pending.signal(); - _progress.signal(); } /** @@ -329,6 +337,13 @@ rust_dom::schedule_task() } void +rust_dom::log_all_state() { + for (uint32_t i = 0; i < _live_domains.size(); i++) { + _live_domains[i]->log_state(); + } +} + +void rust_dom::log_state() { if (!running_tasks.is_empty()) { log(rust_log::TASK, "running tasks:"); @@ -352,8 +367,9 @@ rust_dom::log_state() { if (!dead_tasks.is_empty()) { log(rust_log::TASK, "dead tasks:"); for (size_t i = 0; i < dead_tasks.length(); i++) { - log(rust_log::TASK, "\t task: %s @0x%" PRIxPTR, - dead_tasks[i]->name, dead_tasks[i]); + log(rust_log::TASK, "\t task: %s 0x%" PRIxPTR ", ref_count: %d", + dead_tasks[i], dead_tasks[i]->name, + dead_tasks[i]->ref_count); } } } @@ -384,22 +400,29 @@ rust_dom::start_main_loop() // if progress is made in other domains. if (scheduled_task == NULL) { - log(rust_log::TASK, - "all tasks are blocked, waiting for progress ..."); - if (_log.is_tracing(rust_log::TASK)) + if (_log.is_tracing(rust_log::TASK)) { log_state(); - _progress.wait(); + } log(rust_log::TASK, - "progress made, resuming ..."); + "all tasks are blocked, scheduler yielding ..."); + sync::yield(); + log(rust_log::TASK, + "scheduler resuming ..."); continue; } I(this, scheduled_task->running()); log(rust_log::TASK, - "activating task %s @0x%" PRIxPTR ", sp=0x%" PRIxPTR, - scheduled_task->name, (uintptr_t)scheduled_task, - scheduled_task->rust_sp); + "activating task %s 0x%" PRIxPTR + ", sp=0x%" PRIxPTR + ", ref_count=%d" + ", state: %s", + scheduled_task->name, + (uintptr_t)scheduled_task, + scheduled_task->rust_sp, + scheduled_task->ref_count, + scheduled_task->state_str()); interrupt_flag = 0; @@ -423,21 +446,15 @@ rust_dom::start_main_loop() log(rust_log::DOM, "terminated scheduler loop, reaping dead tasks ..."); while (dead_tasks.length() > 0) { - log(rust_log::DOM, - "waiting for %d dead tasks to become dereferenced ...", - dead_tasks.length()); - - if (_log.is_tracing(rust_log::DOM)) { - for (size_t i = 0; i < dead_tasks.length(); i++) { - log(rust_log::DOM, - "task: %s @0x%" PRIxPTR ", index: %d, ref_count: %d", - dead_tasks[i]->name, dead_tasks[i], i, - dead_tasks[i]->ref_count); - } - } - if (_incoming_message_queue.is_empty()) { - _incoming_message_pending.wait(); + log(rust_log::DOM, + "waiting for %d dead tasks to become dereferenced, " + "scheduler yielding ...", + dead_tasks.length()); + if (_log.is_tracing(rust_log::TASK)) { + log_state(); + } + sync::yield(); } else { drain_incoming_message_queue(); } diff --git a/src/rt/rust_dom.h b/src/rt/rust_dom.h index abf10cef..3aaf635a 100644 --- a/src/rt/rust_dom.h +++ b/src/rt/rust_dom.h @@ -35,13 +35,10 @@ struct rust_dom rust_task *curr_task; int rval; - condition_variable _progress; - hash_map<rust_task *, rust_proxy<rust_task> *> _task_proxies; hash_map<rust_port *, rust_proxy<rust_port> *> _port_proxies; // Incoming messages from other domains. - condition_variable _incoming_message_pending; lock_free_queue _incoming_message_queue; #ifndef __WIN32__ @@ -87,6 +84,7 @@ struct rust_dom int start_main_loop(); void log_state(); + static void log_all_state(); }; // diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h index a89144d7..46ea843f 100644 --- a/src/rt/rust_internal.h +++ b/src/rt/rust_internal.h @@ -38,6 +38,7 @@ extern "C" { #error "Platform not supported." #endif +#include "sync/sync.h" #include "sync/condition_variable.h" #ifndef __i386__ @@ -75,7 +76,7 @@ template <typename T> struct rc_base { - size_t ref_count; + int32_t ref_count; void ref() { ++ref_count; @@ -151,6 +152,7 @@ public: T *& operator[](size_t offset); void push(T *p); T *pop(); + T *peek(); void trim(size_t fill); void swap_delete(T* p); }; diff --git a/src/rt/rust_log.cpp b/src/rt/rust_log.cpp index 48fcd0f1..8e089791 100644 --- a/src/rt/rust_log.cpp +++ b/src/rt/rust_log.cpp @@ -27,6 +27,7 @@ read_type_bit_mask() { bits |= strstr(env_str, "timer") ? rust_log::TIMER : 0; bits |= strstr(env_str, "gc") ? rust_log::GC : 0; bits |= strstr(env_str, "all") ? rust_log::ALL : 0; + bits = strstr(env_str, "none") ? 0 : bits; } return bits; } diff --git a/src/rt/rust_message.cpp b/src/rt/rust_message.cpp index 8b396b4d..1de804c9 100644 --- a/src/rt/rust_message.cpp +++ b/src/rt/rust_message.cpp @@ -90,8 +90,7 @@ send(uint8_t *buffer, size_t buffer_sz, const char* label, rust_task *source, } void data_message::process() { - _port->remote_channel->buffer.enqueue(_buffer); - _port->remote_channel->transmit(); + _port->remote_channel->send(_buffer); _target->log(rust_log::COMM, "<=== received data via message ==="); } diff --git a/src/rt/rust_port.cpp b/src/rt/rust_port.cpp index 0a5b7ee7..c97b5d41 100644 --- a/src/rt/rust_port.cpp +++ b/src/rt/rust_port.cpp @@ -17,16 +17,50 @@ rust_port::~rust_port() { task->log(rust_log::COMM | rust_log::MEM, "~rust_port 0x%" PRIxPTR, (uintptr_t) this); + log_state(); + // Disassociate channels from this port. while (chans.is_empty() == false) { - chans.pop()->disassociate(); + rust_chan *chan = chans.peek(); + chan->disassociate(); } - // We're the only ones holding a reference to the remote channel, so - // clean it up. delete remote_channel; } +bool rust_port::receive(void *dptr) { + for (uint32_t i = 0; i < chans.length(); i++) { + rust_chan *chan = chans[i]; + if (chan->buffer.is_empty() == false) { + chan->buffer.dequeue(dptr); + if (chan->buffer.is_empty() && chan->task->blocked()) { + task->log(rust_log::COMM, + "chan: 0x%" PRIxPTR + " is flushing, wakeup task: 0x%" PRIxPTR, + chan, chan->task); + chan->task->wakeup(this); + } + task->log(rust_log::COMM, "<=== read data ==="); + return true; + } + } + return false; +} + +void rust_port::log_state() { + task->log(rust_log::COMM, + "rust_port: 0x%" PRIxPTR ", associated channel(s): %d", + this, chans.length()); + for (uint32_t i = 0; i < chans.length(); i++) { + rust_chan *chan = chans[i]; + task->log(rust_log::COMM, + "\tchan: 0x%" PRIxPTR ", data pending: %s, remote: %s", + chan, + !chan->buffer.is_empty() ? "yes" : "no", + chan == remote_channel ? "yes" : "no"); + } +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_port.h b/src/rt/rust_port.h index 49a89437..7a58f839 100644 --- a/src/rt/rust_port.h +++ b/src/rt/rust_port.h @@ -15,6 +15,8 @@ public: rust_port(rust_task *task, size_t unit_sz); ~rust_port(); + void log_state(); + bool receive(void *dptr); }; // diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index 279850cb..aca8bca7 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -324,6 +324,11 @@ get_callee_save_fp(uintptr_t *top_of_callee_saves) void rust_task::kill() { + if (dead()) { + // Task is already dead, can't kill what's already dead. + return; + } + // Note the distinction here: kill() is when you're in an upcall // from task A and want to force-fail task B, you do B->kill(). // If you want to fail yourself you do self->fail(upcall_nargs). @@ -334,6 +339,7 @@ rust_task::kill() { if (this == dom->root_task) dom->fail(); + log(rust_log::TASK, "preparing to unwind task: 0x%" PRIxPTR, this); run_on_resume(dom->root_crate->get_unwind_glue()); } @@ -519,6 +525,10 @@ rust_task::free(void *p, bool is_gc) } } +const char * +rust_task::state_str() { + return dom->state_vec_name(state); +} void rust_task::transition(ptr_vec<rust_task> *src, ptr_vec<rust_task> *dst) @@ -556,9 +566,6 @@ rust_task::wakeup(rust_cond *from) A(dom, cond == from, "Cannot wake up blocked task on wrong condition."); transition(&dom->blocked_tasks, &dom->running_tasks); - // TODO: Signaling every time the task is awaken is kind of silly, - // do this a nicer way. - dom->_progress.signal(); I(dom, cond == from); cond = NULL; } diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index b0757e29..90d6f6d9 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -6,11 +6,13 @@ #define LOG_UPCALL_ENTRY(task) \ (task)->dom->get_log().reset_indent(0); \ (task)->log(rust_log::UPCALL, \ - "> UPCALL %s - task: %s @0x%" PRIxPTR \ - " retpc: x%" PRIxPTR, \ + "> UPCALL %s - task: %s 0x%" PRIxPTR \ + " retpc: x%" PRIxPTR \ + " ref_count: %d", \ __FUNCTION__, \ (task)->name, (task), \ - __builtin_return_address(0)); \ + __builtin_return_address(0), \ + (task->ref_count)); \ (task)->dom->get_log().indent(); #else #define LOG_UPCALL_ENTRY(task) \ @@ -21,6 +23,20 @@ (task)->dom->get_log().indent(); #endif +void +log_task_state(rust_task *task, maybe_proxy<rust_task> *target) { + rust_task *delegate = target->delegate(); + if (target->is_proxy()) { + task->log(rust_log::TASK, + "remote task: 0x%" PRIxPTR ", ref_count: %d state: %s", + delegate, delegate->ref_count, delegate->state_str()); + } else { + task->log(rust_log::TASK, + "local task: 0x%" PRIxPTR ", ref_count: %d state: %s", + delegate, delegate->ref_count, delegate->state_str()); + } +} + extern "C" CDECL char const *str_buf(rust_task *task, rust_str *s); extern "C" void upcall_grow_task(rust_task *task, size_t n_frame_bytes) { @@ -31,14 +47,13 @@ extern "C" void upcall_grow_task(rust_task *task, size_t n_frame_bytes) { extern "C" CDECL void upcall_log_int(rust_task *task, int32_t i) { LOG_UPCALL_ENTRY(task); task->log(rust_log::UPCALL | rust_log::ULOG, - "upcall log_int(0x%" PRIx32 " = %" PRId32 " = '%c')", i, i, - (char) i); + "rust: %" PRId32 " (0x%" PRIx32 ")", i, i); } extern "C" CDECL void upcall_log_str(rust_task *task, rust_str *str) { LOG_UPCALL_ENTRY(task); const char *c = str_buf(task, str); - task->log(rust_log::UPCALL | rust_log::ULOG, "upcall log_str(\"%s\")", c); + task->log(rust_log::UPCALL | rust_log::ULOG, "rust: %s", c); } extern "C" CDECL void upcall_trace_word(rust_task *task, uintptr_t i) { @@ -86,26 +101,50 @@ upcall_new_chan(rust_task *task, rust_port *port) { } /** + * Called whenever this channel needs to be flushed. This can happen due to a + * flush statement, or automatically whenever a channel's ref count is + * about to drop to zero. + */ +extern "C" CDECL void +upcall_flush_chan(rust_task *task, rust_chan *chan) { + LOG_UPCALL_ENTRY(task); + rust_dom *dom = task->dom; + task->log(rust_log::UPCALL | rust_log::COMM, + "flush chan: 0x%" PRIxPTR, chan); + + if (chan->buffer.is_empty()) { + return; + } + + A(dom, chan->port->is_proxy() == false, + "Channels to remote ports should be flushed automatically."); + + // Block on the port until this channel has been completely drained + // by the port. + task->block(chan->port); + task->yield(2); +} + +/** * Called whenever the channel's ref count drops to zero. + * + * Cannot Yield: If the task were to unwind, the dropped ref would still + * appear to be live, causing modify-after-free errors. */ extern "C" CDECL void upcall_del_chan(rust_task *task, rust_chan *chan) { LOG_UPCALL_ENTRY(task); - rust_dom *dom = task->dom; + task->log(rust_log::UPCALL | rust_log::MEM | rust_log::COMM, "upcall del_chan(0x%" PRIxPTR ")", (uintptr_t) chan); - I(dom, !chan->ref_count); - - if (!chan->buffer.is_empty() && chan->is_associated()) { - A(dom, !chan->port->is_proxy(), - "Channels to remote ports should be flushed automatically."); - // A target port may still be reading from this channel. - // Block on this channel until it has been completely drained - // by the port. - task->block(chan); - task->yield(2); - return; - } + A(task->dom, chan->ref_count == 0, + "Channel's ref count should be zero."); + + if (chan->is_associated()) { + A(task->dom, chan->buffer.is_empty(), + "Channel's buffer should be empty."); + chan->disassociate(); + } delete chan; } @@ -171,8 +210,7 @@ upcall_send(rust_task *task, rust_chan *chan, void *sptr) { "chan: 0x%" PRIxPTR ", sptr: 0x%" PRIxPTR ", size: %d", (uintptr_t) chan, (uintptr_t) sptr, chan->port->delegate()->unit_sz); - chan->buffer.enqueue(sptr); - chan->transmit(); + chan->send(sptr); task->log(rust_log::COMM, "=== sent data ===>"); } @@ -185,17 +223,8 @@ upcall_recv(rust_task *task, uintptr_t *dptr, rust_port *port) { (uintptr_t) port, (uintptr_t) dptr, port->unit_sz, port->chans.length()); - for (uint32_t i = 0; i < port->chans.length(); i++) { - rust_chan *chan = port->chans[i]; - if (chan->buffer.is_empty() == false) { - chan->buffer.dequeue(dptr); - if (chan->buffer.is_empty() && chan->task->blocked()) { - chan->task->wakeup(chan); - delete chan; - } - task->log(rust_log::COMM, "<=== read data ==="); - return; - } + if (port->receive(dptr)) { + return; } // No data was buffered on any incoming channel, so block this task @@ -222,6 +251,7 @@ extern "C" CDECL void upcall_fail(rust_task *task, char const *expr, extern "C" CDECL void upcall_kill(rust_task *task, maybe_proxy<rust_task> *target) { LOG_UPCALL_ENTRY(task); + log_task_state(task, target); rust_task *target_task = target->delegate(); task->log(rust_log::UPCALL | rust_log::TASK, @@ -247,6 +277,8 @@ upcall_exit(rust_task *task) { LOG_UPCALL_ENTRY(task); task->log(rust_log::UPCALL | rust_log::TASK, "task ref_count: %d", task->ref_count); + A(task->dom, task->ref_count >= 0, + "Task ref_count should not be negative on exit!"); task->die(); task->notify_tasks_waiting_to_join(); task->yield(1); diff --git a/src/rt/rust_util.h b/src/rt/rust_util.h index 42082119..03b7766d 100644 --- a/src/rt/rust_util.h +++ b/src/rt/rust_util.h @@ -70,6 +70,13 @@ ptr_vec<T>::pop() } template <typename T> +T * +ptr_vec<T>::peek() +{ + return data[fill - 1]; +} + +template <typename T> void ptr_vec<T>::trim(size_t sz) { @@ -140,11 +147,20 @@ isaac_init(rust_dom *dom, randctx *rctx) CryptReleaseContext(hProv, 0)); } #else - int fd = open("/dev/urandom", O_RDONLY); - I(dom, fd > 0); - I(dom, read(fd, (void*) &rctx->randrsl, sizeof(rctx->randrsl)) - == sizeof(rctx->randrsl)); - I(dom, close(fd) == 0); + char *rust_seed = getenv("RUST_SEED"); + if (rust_seed != NULL) { + ub4 seed = (ub4) atoi(rust_seed); + for (size_t i = 0; i < RANDSIZ; i ++) { + memcpy(&rctx->randrsl[i], &seed, sizeof(ub4)); + seed = (seed + 0x7ed55d16) + (seed << 12); + } + } else { + int fd = open("/dev/urandom", O_RDONLY); + I(dom, fd > 0); + I(dom, read(fd, (void*) &rctx->randrsl, sizeof(rctx->randrsl)) + == sizeof(rctx->randrsl)); + I(dom, close(fd) == 0); + } #endif randinit(rctx, 1); } diff --git a/src/rt/sync/condition_variable.cpp b/src/rt/sync/condition_variable.cpp index d4032572..c34ab7f4 100644 --- a/src/rt/sync/condition_variable.cpp +++ b/src/rt/sync/condition_variable.cpp @@ -9,14 +9,16 @@ // #define TRACE -condition_variable::condition_variable() { #if defined(__WIN32__) +condition_variable::condition_variable() { _event = CreateEvent(NULL, FALSE, FALSE, NULL); +} #else +condition_variable::condition_variable() { pthread_cond_init(&_cond, NULL); pthread_mutex_init(&_mutex, NULL); -#endif } +#endif condition_variable::~condition_variable() { #if defined(__WIN32__) @@ -31,15 +33,31 @@ condition_variable::~condition_variable() { * Wait indefinitely until condition is signaled. */ void condition_variable::wait() { + timed_wait(0); +} + +void condition_variable::timed_wait(size_t timeout_in_ns) { #ifdef TRACE - printf("waiting on condition_variable: 0x%" PRIxPTR "\n", - (uintptr_t)this); + printf("waiting on condition_variable: 0x%" PRIxPTR " for %d ns. \n", + (uintptr_t) this, (int) timeout_in_ns); #endif #if defined(__WIN32__) WaitForSingleObject(_event, INFINITE); #else pthread_mutex_lock(&_mutex); - pthread_cond_wait(&_cond, &_mutex); + // wait() automatically releases the mutex while it waits, and acquires + // it right before exiting. This allows signal() to acquire the mutex + // when signaling.) + if (timeout_in_ns == 0) { + pthread_cond_wait(&_cond, &_mutex); + } else { + timeval time_val; + gettimeofday(&time_val, NULL); + timespec time_spec; + time_spec.tv_sec = time_val.tv_sec + 0; + time_spec.tv_nsec = time_val.tv_usec * 1000 + timeout_in_ns; + pthread_cond_timedwait(&_cond, &_mutex, &time_spec); + } pthread_mutex_unlock(&_mutex); #endif #ifdef TRACE diff --git a/src/rt/sync/condition_variable.h b/src/rt/sync/condition_variable.h index f847ef99..f336a7f2 100644 --- a/src/rt/sync/condition_variable.h +++ b/src/rt/sync/condition_variable.h @@ -13,6 +13,7 @@ public: virtual ~condition_variable(); void wait(); + void timed_wait(size_t timeout_in_ns); void signal(); }; diff --git a/src/rt/sync/sync.cpp b/src/rt/sync/sync.cpp new file mode 100644 index 00000000..eba51a49 --- /dev/null +++ b/src/rt/sync/sync.cpp @@ -0,0 +1,12 @@ +#include "../globals.h" +#include "sync.h" + +void sync::yield() { +#ifdef __APPLE__ + pthread_yield_np(); +#elif __WIN32__ + +#else + pthread_yield(); +#endif +} diff --git a/src/rt/sync/sync.h b/src/rt/sync/sync.h new file mode 100644 index 00000000..902b5661 --- /dev/null +++ b/src/rt/sync/sync.h @@ -0,0 +1,9 @@ +#ifndef SYNC_H +#define SYNC_H + +class sync { +public: + static void yield(); +}; + +#endif /* SYNC_H */ diff --git a/src/rt/util/array_list.h b/src/rt/util/array_list.h index e6ce55ab..929117f3 100644 --- a/src/rt/util/array_list.h +++ b/src/rt/util/array_list.h @@ -16,7 +16,7 @@ public: int32_t append(T value); int32_t push(T value); T pop(); - T replace(T old_value, T new_value); + bool replace(T old_value, T new_value); int32_t index_of(T value); bool is_empty(); T & operator[](size_t index); @@ -62,16 +62,16 @@ array_list<T>::pop() { /** * Replaces the old_value in the list with the new_value. - * Returns the old_value if the replacement succeeded, or NULL otherwise. + * Returns the true if the replacement succeeded, or false otherwise. */ -template<typename T> T +template<typename T> bool array_list<T>::replace(T old_value, T new_value) { int index = index_of(old_value); if (index < 0) { - return NULL; + return false; } _data[index] = new_value; - return old_value; + return true; } template<typename T> int32_t diff --git a/src/run.py b/src/run.py new file mode 100644 index 00000000..4cce4102 --- /dev/null +++ b/src/run.py @@ -0,0 +1,81 @@ +import os +import sys +import time +import glob +import fnmatch +from optparse import OptionParser + +rustDir = os.path.abspath('.') +rustTestDir = rustDir + "/test"; +rustTestRunPassDir = rustTestDir + "/run-pass"; +rustTestRunFailDir = rustTestDir + "/run-fail"; +rustTestCompileFailDir = rustTestDir + "/run-compile-fail"; +rustTestRunBenchDir = rustTestDir + "/run-bench"; + +parser = OptionParser() +parser.set_usage("run.py [options] pattern : run.py -n 100 \"bas*\" -q"); +parser.add_option("-n", dest="repetitions", + help="number of repetitions", metavar="NUMBER") +parser.add_option("-q", action="store_true", dest="quiet", default=False, + help="suppresses rust log output") +parser.add_option("-p", action="store_true", dest="printSource", + default=False, help="prints the test case's source") +parser.add_option("-s", dest="seed", metavar="NUMBER", default=-1, + help="seeds the rust scheduler, use -1 to generate seeds, " + + " or >= 0 to specify a seed") + +(options, args) = parser.parse_args() + +def getRustTests(filter): + tests = [] + for root, dirnames, filenames in os.walk(rustTestDir): + for filename in fnmatch.filter(filenames, filter + '.rs'): + tests.append(os.path.join(root, filename). + replace(rustDir + "/", "")); + return tests + + +if len(args) != 1: + parser.print_usage(); + sys.exit(0); + +tests = getRustTests(args[0]); + +# Make +for rustProgram in tests: + print "Making: " + rustProgram; + result = os.system("make " + rustProgram.replace(".rs", ".x86")) >> 8; + if (result != 0): + print "Make failed!"; + sys.exit(1); + +if (options.quiet): + os.putenv("RUST_LOG", "none") + +# Rut +totalPassed = 0; +for rustProgram in tests: + repetitions = 1; + if (options.repetitions): + repetitions = int(options.repetitions); + passed = 0; + if (options.printSource): + os.system("cat " + rustProgram); + for i in range(0, repetitions): + print "Running: " + rustProgram + " " + str(i) + \ + " of " + str(repetitions); + if (options.seed): + if (int(options.seed) >= 0): + os.putenv("RUST_SEED", options.seed); + else: + os.putenv("RUST_SEED", str(i)); + result = os.system(rustProgram.replace(".rs", ".x86")); + exitStatus = result >> 8; + signalNumber = result & 0xF; + if (result == 0): + passed += 1; + print "Result for: " + rustProgram + " " + str(passed) + \ + " of " + str(repetitions) + " passed."; + totalPassed += passed; +print "Total: " + str(totalPassed) + " of " + \ + str(len(tests) * repetitions) + " passed."
\ No newline at end of file diff --git a/src/test/run-pass/arith-0.rs b/src/test/run-pass/arith-0.rs new file mode 100644 index 00000000..7587b005 --- /dev/null +++ b/src/test/run-pass/arith-0.rs @@ -0,0 +1,5 @@ +fn main() -> () { + let int a = 10; + log a; + check (a * (a - 1) == 90); +}
\ No newline at end of file diff --git a/src/test/run-pass/arith-1.rs b/src/test/run-pass/arith-1.rs new file mode 100644 index 00000000..bac6a055 --- /dev/null +++ b/src/test/run-pass/arith-1.rs @@ -0,0 +1,22 @@ +fn main() -> () { + let int i32_a = 10; + check(i32_a == 10); + check(i32_a - 10 == 0); + check(i32_a / 10 == 1); + check(i32_a - 20 == -10); + check(i32_a << 10 == 10240); + check(i32_a << 16 == 655360); + check(i32_a * 16 == 160); + check(i32_a * i32_a * i32_a == 1000); + check(i32_a * i32_a * i32_a * i32_a == 10000); + check(((i32_a * i32_a) / i32_a) * i32_a == 100); + check(i32_a * (i32_a - 1) << 2 + i32_a == 368640); + + let int i32_b = 0x10101010; + check(i32_b + 1 - 1 == i32_b); + check(i32_b << 1 == i32_b << 1); + check(i32_b >> 1 == i32_b >> 1); + check((i32_b & (i32_b << 1)) == 0); + log ((i32_b | (i32_b << 1))); + check((i32_b | (i32_b << 1)) == 0x30303030); +}
\ No newline at end of file diff --git a/src/test/run-pass/arith-2.rs b/src/test/run-pass/arith-2.rs new file mode 100644 index 00000000..33a740c8 --- /dev/null +++ b/src/test/run-pass/arith-2.rs @@ -0,0 +1,5 @@ +fn main() -> () { + let int i32_c = 0x10101010; + check (i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3) == + i32_c + (((i32_c * 2) / 3) * 2) + (i32_c - (7 % 3))); +}
\ No newline at end of file diff --git a/src/test/run-pass/basic-1.rs b/src/test/run-pass/basic-1.rs new file mode 100644 index 00000000..bdd7ee25 --- /dev/null +++ b/src/test/run-pass/basic-1.rs @@ -0,0 +1,25 @@ +// -*- rust -*- + +io fn a(chan[int] c) { + c <| 10; +} + +io fn main() { + let port[int] p = port(); + spawn a(chan(p)); + spawn b(chan(p)); + let int n = 0; + n <- p; + n <- p; +// log "Finished."; +} + +io fn b(chan[int] c) { +// log "task b0"; +// log "task b1"; +// log "task b2"; +// log "task b3"; +// log "task b4"; +// log "task b5"; + c <| 10; +}
\ No newline at end of file diff --git a/src/test/run-pass/basic-2.rs b/src/test/run-pass/basic-2.rs new file mode 100644 index 00000000..975a0d4b --- /dev/null +++ b/src/test/run-pass/basic-2.rs @@ -0,0 +1,26 @@ +// -*- rust -*- + +io fn a(chan[int] c) { + log "task a0"; + log "task a1"; + c <| 10; +} + +io fn main() { + let port[int] p = port(); + spawn a(chan(p)); + spawn b(chan(p)); + let int n = 0; + n <- p; + n <- p; + log "Finished."; +} + +io fn b(chan[int] c) { + log "task b0"; + log "task b1"; + log "task b2"; + log "task b2"; + log "task b3"; + c <| 10; +} diff --git a/src/test/run-pass/task-comm-0.rs b/src/test/run-pass/task-comm-0.rs index 5992ba5c..28294422 100644 --- a/src/test/run-pass/task-comm-0.rs +++ b/src/test/run-pass/task-comm-0.rs @@ -15,5 +15,5 @@ io fn test05() { let int value <- po; value <- po; value <- po; - log value; + check(value == 30); } diff --git a/src/test/run-pass/task-comm-2.rs b/src/test/run-pass/task-comm-2.rs index 9c85da34..864d49de 100644 --- a/src/test/run-pass/task-comm-2.rs +++ b/src/test/run-pass/task-comm-2.rs @@ -1,8 +1,8 @@ fn main() -> () { - log "===== THREADS ====="; + log "===== SPAWNING and JOINING TASKS ====="; + test00(false); + log "===== SPAWNING and JOINING THREAD TASKS ====="; test00(true); - log "====== TASKS ======"; - // test00(false); } fn start(int task_number) { @@ -15,7 +15,7 @@ fn start(int task_number) { } fn test00(bool create_threads) { - let int number_of_tasks = 0; + let int number_of_tasks = 8; let int i = 0; let vec[task] tasks = vec(); diff --git a/src/test/run-pass/task-comm-3.rs b/src/test/run-pass/task-comm-3.rs index 6dd620cc..9a3f9e16 100644 --- a/src/test/run-pass/task-comm-3.rs +++ b/src/test/run-pass/task-comm-3.rs @@ -1,6 +1,8 @@ io fn main() -> () { - log "===== THREADS ====="; + log "===== WITHOUT THREADS ====="; test00(false); + log "====== WITH THREADS ======"; + test00(true); } io fn test00_start(chan[int] ch, int message, int count) { @@ -15,8 +17,9 @@ io fn test00_start(chan[int] ch, int message, int count) { } io fn test00(bool is_multithreaded) { - let int number_of_tasks = 1; - let int number_of_messages = 0; + let int number_of_tasks = 16; + let int number_of_messages = 4; + log "Creating tasks"; let port[int] po = port(); @@ -27,13 +30,13 @@ io fn test00(bool is_multithreaded) { // Create and spawn tasks... let vec[task] tasks = vec(); while (i < number_of_tasks) { - i = i + 1; if (is_multithreaded) { tasks += vec( spawn thread test00_start(ch, i, number_of_messages)); } else { tasks += vec(spawn test00_start(ch, i, number_of_messages)); } + i = i + 1; } // Read from spawned tasks... @@ -53,7 +56,7 @@ io fn test00(bool is_multithreaded) { } log "Completed: Final number is: "; - check (sum + 1 == number_of_messages * - (number_of_tasks * number_of_tasks + number_of_tasks) / 2); - log sum; -}
\ No newline at end of file + // check (sum == (((number_of_tasks * (number_of_tasks - 1)) / 2) * + // number_of_messages)); + check (sum == 480); +} diff --git a/src/test/run-pass/task-comm-6.rs b/src/test/run-pass/task-comm-6.rs index c579a98c..2774c0ba 100644 --- a/src/test/run-pass/task-comm-6.rs +++ b/src/test/run-pass/task-comm-6.rs @@ -31,6 +31,8 @@ io fn test00() { r <- p; sum += r; i += 1; } - - check (sum == 4 * ((number_of_messages * (number_of_messages - 1)) / 2)); + + check (sum == 1998000); + // check (sum == 4 * ((number_of_messages * + // (number_of_messages - 1)) / 2)); }
\ No newline at end of file diff --git a/src/test/run-pass/task-comm.rs b/src/test/run-pass/task-comm.rs index ef71c6e1..3c5d3216 100644 --- a/src/test/run-pass/task-comm.rs +++ b/src/test/run-pass/task-comm.rs @@ -1,11 +1,11 @@ -fn main() -> () { - // test00(true); +io fn main() -> () { + test00(true); // test01(); - // test02(); - // test03(); - // test04(); - // test05(); + test02(); + test03(); + test04(); + test05(); test06(); } @@ -22,7 +22,7 @@ io fn test00_start(chan[int] ch, int message, int count) { io fn test00(bool is_multithreaded) { let int number_of_tasks = 1; - let int number_of_messages = 64; + let int number_of_messages = 4; log "Creating tasks"; let port[int] po = port(); @@ -103,7 +103,7 @@ fn test04_start() { fn test04() { log "Spawning lots of tasks."; - let int i = 64; + let int i = 4; while (i > 0) { i = i - 1; spawn thread test04_start(); @@ -139,7 +139,7 @@ fn test06_start(int task_number) { } fn test06() { - let int number_of_tasks = 32; + let int number_of_tasks = 4; log "Creating tasks"; let int i = 0; |