auto merge of #10058 : alexcrichton/rust/uv-crate, r=brson

This is one of the final steps needed to complete #9128. It still needs a little bit of polish before closing that issue, but it's in a pretty much "done" state now.

The idea here is that the entire event loop implementation using libuv is now housed in `librustuv` as a completely separate library. This library is then injected (via `extern mod rustv`) into executable builds (similarly to how libstd is injected, tunable via `#[no_uv]`) to bring in the "rust blessed event loop implementation."

Codegen-wise, there is a new `event_loop_factory` language item which is tagged on a function with 0 arguments returning `~EventLoop`. This function's symbol is then inserted into the crate map for an executable crate, and if there is no definition of the `event_loop_factory` language item then the value is null.

What this means is that embedding rust as a library in another language just got a little harder. Libraries don't have crate maps, which means that there's no way to find the event loop implementation to spin up the runtime. That being said, it's always possible to build the runtime manually. This request also makes more runtime components public which should probably be public anyway. This new public-ness should allow custom scheduler setups everywhere regardless of whether you follow the `rt::start `path.
This commit is contained in:
bors 2013-10-29 09:36:47 -07:00
commit 52f42f1638
37 changed files with 7127 additions and 185 deletions

View File

@ -221,6 +221,7 @@ CFG_LIBRUSTC_$(1) :=$(call CFG_LIB_NAME_$(1),rustc)
CFG_LIBSYNTAX_$(1) :=$(call CFG_LIB_NAME_$(1),syntax)
CFG_LIBRUSTPKG_$(1) :=$(call CFG_LIB_NAME_$(1),rustpkg)
CFG_LIBRUSTDOC_$(1) :=$(call CFG_LIB_NAME_$(1),rustdoc)
CFG_LIBRUSTUV_$(1) :=$(call CFG_LIB_NAME_$(1),rustuv)
EXTRALIB_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),extra)
STDLIB_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),std)
@ -228,12 +229,14 @@ LIBRUSTC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustc)
LIBSYNTAX_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),syntax)
LIBRUSTPKG_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustpkg)
LIBRUSTDOC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustdoc)
LIBRUSTUV_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustuv)
EXTRALIB_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),extra)
STDLIB_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),std)
LIBRUSTC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustc)
LIBSYNTAX_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),syntax)
LIBRUSTPKG_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustpkg)
LIBRUSTDOC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustdoc)
LIBRUSTUV_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustuv)
endef
@ -289,6 +292,14 @@ EXTRALIB_CRATE := $(S)src/libextra/extra.rs
EXTRALIB_INPUTS := $(wildcard $(addprefix $(S)src/libextra/, \
*.rs */*.rs))
######################################################################
# Rust UV library variables
######################################################################
LIBRUSTUV_CRATE := $(S)src/librustuv/rustuv.rs
LIBRUSTUV_INPUTS := $(wildcard $(addprefix $(S)src/librustuv/, \
*.rs */*.rs))
######################################################################
# rustc crate variables
######################################################################
@ -410,6 +421,11 @@ else
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTC_$(3))
TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3) = \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2))
HLIBRUSTUV_DEFAULT$(1)_H_$(3) = \
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTUV_$(3))
TLIBRUSTUV_DEFAULT$(1)_T_$(2)_H_$(3) = \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2))
endif
# Preqrequisites for using the stageN compiler
@ -421,6 +437,7 @@ HSREQ$(1)_H_$(3) = \
$$(HEXTRALIB_DEFAULT$(1)_H_$(3)) \
$$(HLIBSYNTAX_DEFAULT$(1)_H_$(3)) \
$$(HLIBRUSTC_DEFAULT$(1)_H_$(3)) \
$$(HLIBRUSTUV_DEFAULT$(1)_H_$(3)) \
$$(MKFILE_DEPS)
# Prerequisites for using the stageN compiler to build target artifacts
@ -433,7 +450,8 @@ TSREQ$(1)_T_$(2)_H_$(3) = \
SREQ$(1)_T_$(2)_H_$(3) = \
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2))
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2))
# Prerequisites for a working stageN compiler and libraries, for a specific target
CSREQ$(1)_T_$(2)_H_$(3) = \
@ -447,7 +465,8 @@ CSREQ$(1)_T_$(2)_H_$(3) = \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2))
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2))
ifeq ($(1),0)
# Don't run the the stage0 compiler under valgrind - that ship has sailed

View File

@ -73,6 +73,7 @@ clean$(1)_H_$(2):
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUNTIME_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_STDLIB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_EXTRALIB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTUV_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTC_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBSYNTAX_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(STDLIB_GLOB_$(2))
@ -103,10 +104,12 @@ clean$(1)_T_$(2)_H_$(3):
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(STDLIB_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(EXTRALIB_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTUV_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTC_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBSYNTAX_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTPKG_GLOB_$(2))

View File

@ -30,6 +30,7 @@ $$(HBIN$(2)_H_$(4))/rustc$$(X_$(4)): \
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \
$$(HSTDLIB_DEFAULT$(2)_H_$(4)) \
$$(HEXTRALIB_DEFAULT$(2)_H_$(4)) \
$$(HLIBRUSTUV_DEFAULT$(2)_H_$(4)) \
| $$(HBIN$(2)_H_$(4))/
@$$(call E, cp: $$@)
@ -42,6 +43,7 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)): \
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \
$$(HSTDLIB_DEFAULT$(2)_H_$(4)) \
$$(HEXTRALIB_DEFAULT$(2)_H_$(4)) \
$$(HLIBRUSTUV_DEFAULT$(2)_H_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
@ -58,6 +60,7 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)): \
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \
$$(HSTDLIB_DEFAULT$(2)_H_$(4)) \
$$(HEXTRALIB_DEFAULT$(2)_H_$(4)) \
$$(HLIBRUSTUV_DEFAULT$(2)_H_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_GLOB_$(4)),$$(notdir $$@))
@ -80,7 +83,7 @@ $$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)): \
@$$(call E, cp: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(4)),$$(notdir $$@))
$$(Q)cp $$< $$@
# Subtle: We do not let the shell expand $(STDLIB_DSYM_GLOB) directly rather
# Subtle: We do not let the shell expand $$(STDLIB_DSYM_GLOB) directly rather
# we use Make's $$(wildcard) facility. The reason is that, on mac, when using
# USE_SNAPSHOT_STDLIB, we copy the std.dylib file out of the snapshot.
# In that case, there is no .dSYM file. Annoyingly, bash then refuses to expand
@ -105,6 +108,19 @@ $$(HLIB$(2)_H_$(4))/$(CFG_EXTRALIB_$(4)): \
$$(HLIB$(2)_H_$(4))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(4)),$$(notdir $$@))
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTUV_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTUV_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
$$(Q)cp $$< $$@
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTUV_GLOB_$(4)) \
$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTUV_DSYM_GLOB_$(4))) \
$$(HLIB$(2)_H_$(4))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
$$(HLIB$(2)_H_$(4))/libstd.rlib: \
$$(TLIB$(1)_T_$(4)_H_$(3))/libstd.rlib \
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \

View File

@ -91,6 +91,7 @@ install-target-$(1)-host-$(2): $$(TSREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(SREQ$$(ISTAG
$$(Q)$$(call INSTALL_LIB,$$(CFG_RUNTIME_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(STDLIB_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(EXTRALIB_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(LIBRUSTUV_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,libmorestack.a)
endef
@ -104,6 +105,7 @@ install-target-$(1)-host-$(2): $$(CSREQ$$(ISTAGE)_T_$(1)_H_$(2))
$$(Q)$$(call INSTALL_LIB,$$(CFG_RUSTLLVM_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(STDLIB_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(EXTRALIB_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(LIBRUSTUV_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(LIBRUSTC_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(LIBSYNTAX_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(LIBRUSTPKG_GLOB_$(1)))
@ -143,6 +145,7 @@ install-host: $(CSREQ$(ISTAGE)_T_$(CFG_BUILD_TRIPLE)_H_$(CFG_BUILD_TRIPLE))
$(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(STDLIB_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(EXTRALIB_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTUV_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTC_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(LIBSYNTAX_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD_TRIPLE)))
@ -168,6 +171,7 @@ uninstall:
$(Q)for i in \
$(call HOST_LIB_FROM_HL_GLOB,$(STDLIB_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(EXTRALIB_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTUV_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTC_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBSYNTAX_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD_TRIPLE))) \
@ -230,6 +234,7 @@ install-runtime-target-$(1)-host-$(2): $$(TSREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(SREQ
$(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(CFG_RUNTIME_$(1)),$(CFG_RUNTIME_PUSH_DIR))
$(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(STDLIB_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR))
$(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(EXTRALIB_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR))
$(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(LIBRUSTUV_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR))
endef
define INSTALL_RUNTIME_TARGET_CLEANUP_N
@ -238,6 +243,7 @@ install-runtime-target-$(1)-cleanup:
$(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(CFG_RUNTIME_$(1)))
$(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(STDLIB_GLOB_$(1)))
$(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(EXTRALIB_GLOB_$(1)))
$(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(LIBRUSTUV_GLOB_$(1)))
endef
$(eval $(call INSTALL_RUNTIME_TARGET_N,arm-linux-androideabi,$(CFG_BUILD_TRIPLE)))

View File

@ -148,7 +148,7 @@ $$(RT_BUILD_DIR_$(1)_$(2))/$(CFG_RUNTIME_$(1)): $$(RUNTIME_OBJS_$(1)_$(2)) $$(MK
# These could go in rt.mk or rustllvm.mk, they're needed for both.
# This regexp has a single $, escaped twice
# This regexp has a single $$ escaped twice
$(1)/%.bsd.def: %.def.in $$(MKFILE_DEPS)
@$$(call E, def: $$@)
$$(Q)echo "{" > $$@

View File

@ -42,6 +42,11 @@ $(HLIB0_H_$(CFG_BUILD_TRIPLE))/$(CFG_EXTRALIB_$(CFG_BUILD_TRIPLE)): \
| $(HLIB0_H_$(CFG_BUILD_TRIPLE))/
$(Q)touch $@
$(HLIB0_H_$(CFG_BUILD_TRIPLE))/$(CFG_LIBRUSTUV_$(CFG_BUILD_TRIPLE)): \
$(HBIN0_H_$(CFG_BUILD_TRIPLE))/rustc$(X_$(CFG_BUILD_TRIPLE)) \
| $(HLIB0_H_$(CFG_BUILD_TRIPLE))/
$(Q)touch $@
$(HLIB0_H_$(CFG_BUILD_TRIPLE))/$(CFG_LIBRUSTC_$(CFG_BUILD_TRIPLE)): \
$(HBIN0_H_$(CFG_BUILD_TRIPLE))/rustc$(X_$(CFG_BUILD_TRIPLE)) \
| $(HLIB0_H_$(CFG_BUILD_TRIPLE))/
@ -81,9 +86,9 @@ $$(HLIB0_H_$(1))/$(CFG_STDLIB_$(1)): \
$$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_STDLIB_$(1)) \
| $(HLIB0_H_$(1))/
@$$(call E, cp: $$@)
$$(call CHECK_FOR_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(4)),$$(notdir $$@))
$$(call CHECK_FOR_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(4)),$$(notdir $$@))
$$(Q)cp $$(TLIB$(2)_T_$(1)_H_$(3))/$(STDLIB_GLOB_$(1)) $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(4)),$$(notdir $$@))
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(4)),$$(notdir $$@))
$$(HLIB0_H_$(1))/$(CFG_EXTRALIB_$(1)): \
$$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_EXTRALIB_$(1)) \
@ -93,6 +98,18 @@ $$(HLIB0_H_$(1))/$(CFG_EXTRALIB_$(1)): \
$$(Q)cp $$(TLIB$(2)_T_$(1)_H_$(3))/$(EXTRALIB_GLOB_$(1)) $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(4)),$$(notdir $$@))
$$(HLIB0_H_$(1))/$(CFG_LIBRUSTUV_$(1)):
touch $$@
# NOTE: this should get uncommented after a snapshot and the rule above this can
# get deleted, right now we're not expecting a librustuv in a snapshot.
# $$(HLIB0_H_$(1))/$(CFG_LIBRUSTUV_$(1)): \
# $$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_LIBRUSTUV_$(1)) \
# | $(HLIB0_H_$(1))/
# @$$(call E, cp: $$@)
# $$(call CHECK_FOR_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
# $$(Q)cp $$(TLIB$(2)_T_$(1)_H_$(3))/$(LIBRUSTUV_GLOB_$(1)) $$@
# $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
$$(HLIB0_H_$(1))/$(CFG_LIBRUSTC_$(1)): \
$$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_LIBRUSTC_$(1)) \
| $(HLIB0_H_$(1))/

View File

@ -73,11 +73,22 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)): \
$$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(2)),$$(notdir $$@))
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2)): \
$$(LIBRUSTUV_CRATE) $$(LIBRUSTUV_INPUTS) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(2)),$$(notdir $$@))
$$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(2)),$$(notdir $$@))
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \
$$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
$$(TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3)) \
$$(TEXTRALIB_DEFAULT$(1)_T_$(2)_H_$(3)) \
$$(TLIBRUSTUV_DEFAULT$(1)_T_$(2)_H_$(3)) \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_GLOB_$(2)),$$(notdir $$@))

View File

@ -14,7 +14,7 @@
######################################################################
# The names of crates that must be tested
TEST_TARGET_CRATES = std extra
TEST_TARGET_CRATES = std extra rustuv
TEST_HOST_CRATES = rustpkg rustc rustdoc syntax
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
@ -164,6 +164,8 @@ $(info check: android device test dir $(CFG_ADB_TEST_DIR) ready \
$(CFG_ADB_TEST_DIR)) \
$(shell adb push $(TLIB2_T_arm-linux-androideabi_H_$(CFG_BUILD_TRIPLE))/$(EXTRALIB_GLOB_arm-linux-androideabi) \
$(CFG_ADB_TEST_DIR)) \
$(shell adb push $(TLIB2_T_arm-linux-androideabi_H_$(CFG_BUILD_TRIPLE))/$(LIBRUSTUV_GLOB_arm-linux-androideabi) \
$(CFG_ADB_TEST_DIR)) \
)
else
CFG_ADB_TEST_DIR=
@ -189,6 +191,7 @@ check-test: cleantestlibs cleantmptestlogs all check-stage2-rfail
check-lite: cleantestlibs cleantmptestlogs \
check-stage2-std check-stage2-extra check-stage2-rpass \
check-stage2-rustuv \
check-stage2-rustpkg \
check-stage2-rfail check-stage2-cfail
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
@ -333,7 +336,8 @@ define TEST_RUNNER
# test crates without rebuilding std and extra first
ifeq ($(NO_REBUILD),)
STDTESTDEP_$(1)_$(2)_$(3) = $$(SREQ$(1)_T_$(2)_H_$(3)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_EXTRALIB_$(2))
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_EXTRALIB_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTUV_$(2))
else
STDTESTDEP_$(1)_$(2)_$(3) =
endif
@ -350,6 +354,12 @@ $(3)/stage$(1)/test/extratest-$(2)$$(X_$(2)): \
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
$(3)/stage$(1)/test/rustuvtest-$(2)$$(X_$(2)): \
$$(LIBRUSTUV_CRATE) $$(LIBRUSTUV_INPUTS) \
$$(STDTESTDEP_$(1)_$(2)_$(3))
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
$(3)/stage$(1)/test/syntaxtest-$(2)$$(X_$(2)): \
$$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \
$$(STDTESTDEP_$(1)_$(2)_$(3))

View File

@ -30,6 +30,7 @@ snapshot_files = {
"lib/libextra-*.so",
"lib/librustc-*.so",
"lib/libsyntax-*.so",
"lib/librustuv-*.so",
"lib/librustrt.so",
"lib/librustllvm.so"],
"macos": ["bin/rustc",
@ -37,6 +38,7 @@ snapshot_files = {
"lib/libextra-*.dylib",
"lib/librustc-*.dylib",
"lib/libsyntax-*.dylib",
"lib/librustuv-*.dylib",
"lib/librustrt.dylib",
"lib/librustllvm.dylib"],
"winnt": ["bin/rustc.exe",
@ -44,6 +46,7 @@ snapshot_files = {
"bin/extra-*.dll",
"bin/rustc-*.dll",
"bin/syntax-*.dll",
"bin/rustuv-*.dll",
"bin/rustrt.dll",
"bin/rustllvm.dll"],
"freebsd": ["bin/rustc",
@ -51,6 +54,7 @@ snapshot_files = {
"lib/libextra-*.so",
"lib/librustc-*.so",
"lib/libsyntax-*.so",
"lib/librustuv-*.so",
"lib/librustrt.so",
"lib/librustllvm.so"]
}

View File

@ -35,6 +35,10 @@ fn use_std(crate: &ast::Crate) -> bool {
!attr::contains_name(crate.attrs, "no_std")
}
fn use_uv(crate: &ast::Crate) -> bool {
!attr::contains_name(crate.attrs, "no_uv")
}
fn no_prelude(attrs: &[ast::Attribute]) -> bool {
attr::contains_name(attrs, "no_implicit_prelude")
}
@ -53,19 +57,30 @@ struct StandardLibraryInjector {
impl fold::ast_fold for StandardLibraryInjector {
fn fold_crate(&self, crate: ast::Crate) -> ast::Crate {
let version = STD_VERSION.to_managed();
let vi1 = ast::view_item {
let vers_item = attr::mk_name_value_item_str(@"vers", version);
let mut vis = ~[ast::view_item {
node: ast::view_item_extern_mod(self.sess.ident_of("std"),
None,
~[],
~[vers_item.clone()],
ast::DUMMY_NODE_ID),
attrs: ~[
attr::mk_attr(attr::mk_name_value_item_str(@"vers", version))
],
attrs: ~[],
vis: ast::private,
span: dummy_sp()
};
}];
let vis = vec::append(~[vi1], crate.module.view_items);
if use_uv(&crate) && !*self.sess.building_library {
vis.push(ast::view_item {
node: ast::view_item_extern_mod(self.sess.ident_of("rustuv"),
None,
~[vers_item],
ast::DUMMY_NODE_ID),
attrs: ~[],
vis: ast::private,
span: dummy_sp()
});
}
vis.push_all(crate.module.view_items);
let mut new_module = ast::_mod {
view_items: vis,
..crate.module.clone()

View File

@ -24,10 +24,9 @@ use driver::session::Session;
use metadata::csearch::each_lang_item;
use metadata::cstore::iter_crate_data;
use middle::ty::{BuiltinBound, BoundFreeze, BoundSend, BoundSized};
use syntax::ast::{Crate, DefId, MetaItem};
use syntax::ast;
use syntax::ast_util::local_def;
use syntax::attr::AttrMetaMethods;
use syntax::ast::{item};
use syntax::visit;
use syntax::visit::Visitor;
@ -81,20 +80,22 @@ pub enum LangItem {
TyDescStructLangItem, // 36
TyVisitorTraitLangItem, // 37
OpaqueStructLangItem, // 38
EventLoopFactoryLangItem, // 39
}
pub struct LanguageItems {
items: [Option<DefId>, ..39]
items: [Option<ast::DefId>, ..40]
}
impl LanguageItems {
pub fn new() -> LanguageItems {
LanguageItems {
items: [ None, ..39 ]
items: [ None, ..40 ]
}
}
pub fn items<'a>(&'a self) -> Enumerate<vec::VecIterator<'a, Option<DefId>>> {
pub fn items<'a>(&'a self) -> Enumerate<vec::VecIterator<'a, Option<ast::DefId>>> {
self.items.iter().enumerate()
}
@ -145,13 +146,15 @@ impl LanguageItems {
37 => "ty_visitor",
38 => "opaque",
39 => "event_loop_factory",
_ => "???"
}
}
// FIXME #4621: Method macros sure would be nice here.
pub fn require(&self, it: LangItem) -> Result<DefId, ~str> {
pub fn require(&self, it: LangItem) -> Result<ast::DefId, ~str> {
match self.items[it as uint] {
Some(id) => Ok(id),
None => Err(format!("requires `{}` lang_item",
@ -159,7 +162,7 @@ impl LanguageItems {
}
}
pub fn to_builtin_kind(&self, id: DefId) -> Option<BuiltinBound> {
pub fn to_builtin_kind(&self, id: ast::DefId) -> Option<BuiltinBound> {
if Some(id) == self.freeze_trait() {
Some(BoundFreeze)
} else if Some(id) == self.send_trait() {
@ -171,162 +174,166 @@ impl LanguageItems {
}
}
pub fn freeze_trait(&self) -> Option<DefId> {
pub fn freeze_trait(&self) -> Option<ast::DefId> {
self.items[FreezeTraitLangItem as uint]
}
pub fn send_trait(&self) -> Option<DefId> {
pub fn send_trait(&self) -> Option<ast::DefId> {
self.items[SendTraitLangItem as uint]
}
pub fn sized_trait(&self) -> Option<DefId> {
pub fn sized_trait(&self) -> Option<ast::DefId> {
self.items[SizedTraitLangItem as uint]
}
pub fn drop_trait(&self) -> Option<DefId> {
pub fn drop_trait(&self) -> Option<ast::DefId> {
self.items[DropTraitLangItem as uint]
}
pub fn add_trait(&self) -> Option<DefId> {
pub fn add_trait(&self) -> Option<ast::DefId> {
self.items[AddTraitLangItem as uint]
}
pub fn sub_trait(&self) -> Option<DefId> {
pub fn sub_trait(&self) -> Option<ast::DefId> {
self.items[SubTraitLangItem as uint]
}
pub fn mul_trait(&self) -> Option<DefId> {
pub fn mul_trait(&self) -> Option<ast::DefId> {
self.items[MulTraitLangItem as uint]
}
pub fn div_trait(&self) -> Option<DefId> {
pub fn div_trait(&self) -> Option<ast::DefId> {
self.items[DivTraitLangItem as uint]
}
pub fn rem_trait(&self) -> Option<DefId> {
pub fn rem_trait(&self) -> Option<ast::DefId> {
self.items[RemTraitLangItem as uint]
}
pub fn neg_trait(&self) -> Option<DefId> {
pub fn neg_trait(&self) -> Option<ast::DefId> {
self.items[NegTraitLangItem as uint]
}
pub fn not_trait(&self) -> Option<DefId> {
pub fn not_trait(&self) -> Option<ast::DefId> {
self.items[NotTraitLangItem as uint]
}
pub fn bitxor_trait(&self) -> Option<DefId> {
pub fn bitxor_trait(&self) -> Option<ast::DefId> {
self.items[BitXorTraitLangItem as uint]
}
pub fn bitand_trait(&self) -> Option<DefId> {
pub fn bitand_trait(&self) -> Option<ast::DefId> {
self.items[BitAndTraitLangItem as uint]
}
pub fn bitor_trait(&self) -> Option<DefId> {
pub fn bitor_trait(&self) -> Option<ast::DefId> {
self.items[BitOrTraitLangItem as uint]
}
pub fn shl_trait(&self) -> Option<DefId> {
pub fn shl_trait(&self) -> Option<ast::DefId> {
self.items[ShlTraitLangItem as uint]
}
pub fn shr_trait(&self) -> Option<DefId> {
pub fn shr_trait(&self) -> Option<ast::DefId> {
self.items[ShrTraitLangItem as uint]
}
pub fn index_trait(&self) -> Option<DefId> {
pub fn index_trait(&self) -> Option<ast::DefId> {
self.items[IndexTraitLangItem as uint]
}
pub fn eq_trait(&self) -> Option<DefId> {
pub fn eq_trait(&self) -> Option<ast::DefId> {
self.items[EqTraitLangItem as uint]
}
pub fn ord_trait(&self) -> Option<DefId> {
pub fn ord_trait(&self) -> Option<ast::DefId> {
self.items[OrdTraitLangItem as uint]
}
pub fn str_eq_fn(&self) -> Option<DefId> {
pub fn str_eq_fn(&self) -> Option<ast::DefId> {
self.items[StrEqFnLangItem as uint]
}
pub fn uniq_str_eq_fn(&self) -> Option<DefId> {
pub fn uniq_str_eq_fn(&self) -> Option<ast::DefId> {
self.items[UniqStrEqFnLangItem as uint]
}
pub fn fail_fn(&self) -> Option<DefId> {
pub fn fail_fn(&self) -> Option<ast::DefId> {
self.items[FailFnLangItem as uint]
}
pub fn fail_bounds_check_fn(&self) -> Option<DefId> {
pub fn fail_bounds_check_fn(&self) -> Option<ast::DefId> {
self.items[FailBoundsCheckFnLangItem as uint]
}
pub fn exchange_malloc_fn(&self) -> Option<DefId> {
pub fn exchange_malloc_fn(&self) -> Option<ast::DefId> {
self.items[ExchangeMallocFnLangItem as uint]
}
pub fn closure_exchange_malloc_fn(&self) -> Option<DefId> {
pub fn closure_exchange_malloc_fn(&self) -> Option<ast::DefId> {
self.items[ClosureExchangeMallocFnLangItem as uint]
}
pub fn exchange_free_fn(&self) -> Option<DefId> {
pub fn exchange_free_fn(&self) -> Option<ast::DefId> {
self.items[ExchangeFreeFnLangItem as uint]
}
pub fn malloc_fn(&self) -> Option<DefId> {
pub fn malloc_fn(&self) -> Option<ast::DefId> {
self.items[MallocFnLangItem as uint]
}
pub fn free_fn(&self) -> Option<DefId> {
pub fn free_fn(&self) -> Option<ast::DefId> {
self.items[FreeFnLangItem as uint]
}
pub fn borrow_as_imm_fn(&self) -> Option<DefId> {
pub fn borrow_as_imm_fn(&self) -> Option<ast::DefId> {
self.items[BorrowAsImmFnLangItem as uint]
}
pub fn borrow_as_mut_fn(&self) -> Option<DefId> {
pub fn borrow_as_mut_fn(&self) -> Option<ast::DefId> {
self.items[BorrowAsMutFnLangItem as uint]
}
pub fn return_to_mut_fn(&self) -> Option<DefId> {
pub fn return_to_mut_fn(&self) -> Option<ast::DefId> {
self.items[ReturnToMutFnLangItem as uint]
}
pub fn check_not_borrowed_fn(&self) -> Option<DefId> {
pub fn check_not_borrowed_fn(&self) -> Option<ast::DefId> {
self.items[CheckNotBorrowedFnLangItem as uint]
}
pub fn strdup_uniq_fn(&self) -> Option<DefId> {
pub fn strdup_uniq_fn(&self) -> Option<ast::DefId> {
self.items[StrDupUniqFnLangItem as uint]
}
pub fn record_borrow_fn(&self) -> Option<DefId> {
pub fn record_borrow_fn(&self) -> Option<ast::DefId> {
self.items[RecordBorrowFnLangItem as uint]
}
pub fn unrecord_borrow_fn(&self) -> Option<DefId> {
pub fn unrecord_borrow_fn(&self) -> Option<ast::DefId> {
self.items[UnrecordBorrowFnLangItem as uint]
}
pub fn start_fn(&self) -> Option<DefId> {
pub fn start_fn(&self) -> Option<ast::DefId> {
self.items[StartFnLangItem as uint]
}
pub fn ty_desc(&self) -> Option<DefId> {
pub fn ty_desc(&self) -> Option<ast::DefId> {
self.items[TyDescStructLangItem as uint]
}
pub fn ty_visitor(&self) -> Option<DefId> {
pub fn ty_visitor(&self) -> Option<ast::DefId> {
self.items[TyVisitorTraitLangItem as uint]
}
pub fn opaque(&self) -> Option<DefId> {
pub fn opaque(&self) -> Option<ast::DefId> {
self.items[OpaqueStructLangItem as uint]
}
pub fn event_loop_factory(&self) -> Option<ast::DefId> {
self.items[EventLoopFactoryLangItem as uint]
}
}
struct LanguageItemCollector<'self> {
struct LanguageItemCollector {
items: LanguageItems,
crate: &'self Crate,
session: Session,
item_refs: HashMap<&'static str, uint>,
}
struct LanguageItemVisitor<'self> {
this: *mut LanguageItemCollector<'self>,
this: &'self mut LanguageItemCollector,
}
impl<'self> Visitor<()> for LanguageItemVisitor<'self> {
fn visit_item(&mut self, item: @ast::item, _: ()) {
match extract(item.attrs) {
Some(value) => {
let item_index = self.this.item_refs.find_equiv(&value).map(|x| *x);
fn visit_item(&mut self, item:@item, _:()) {
for attribute in item.attrs.iter() {
unsafe {
(*self.this).match_and_collect_meta_item(
local_def(item.id),
attribute.node.value
);
match item_index {
Some(item_index) => {
self.this.collect_item(item_index, local_def(item.id))
}
None => {}
}
}
None => {}
}
visit::walk_item(self, item, ());
}
}
impl<'self> LanguageItemCollector<'self> {
pub fn new<'a>(crate: &'a Crate, session: Session)
-> LanguageItemCollector<'a> {
impl LanguageItemCollector {
pub fn new(session: Session) -> LanguageItemCollector {
let mut item_refs = HashMap::new();
item_refs.insert("freeze", FreezeTraitLangItem as uint);
@ -374,27 +381,16 @@ impl<'self> LanguageItemCollector<'self> {
item_refs.insert("ty_desc", TyDescStructLangItem as uint);
item_refs.insert("ty_visitor", TyVisitorTraitLangItem as uint);
item_refs.insert("opaque", OpaqueStructLangItem as uint);
item_refs.insert("event_loop_factory", EventLoopFactoryLangItem as uint);
LanguageItemCollector {
crate: crate,
session: session,
items: LanguageItems::new(),
item_refs: item_refs
}
}
pub fn match_and_collect_meta_item(&mut self,
item_def_id: DefId,
meta_item: &MetaItem) {
match meta_item.name_str_pair() {
Some((key, value)) => {
self.match_and_collect_item(item_def_id, key, value);
}
None => {} // skip
}
}
pub fn collect_item(&mut self, item_index: uint, item_def_id: DefId) {
pub fn collect_item(&mut self, item_index: uint, item_def_id: ast::DefId) {
// Check for duplicates.
match self.items.items[item_index] {
Some(original_def_id) if original_def_id != item_def_id => {
@ -410,33 +406,9 @@ impl<'self> LanguageItemCollector<'self> {
self.items.items[item_index] = Some(item_def_id);
}
pub fn match_and_collect_item(&mut self,
item_def_id: DefId,
key: &str,
value: @str) {
if "lang" != key {
return; // Didn't match.
}
let item_index = self.item_refs.find_equiv(&value).map(|x| *x);
// prevent borrow checker from considering ^~~~~~~~~~~
// self to be borrowed (annoying)
match item_index {
Some(item_index) => {
self.collect_item(item_index, item_def_id);
}
None => {
// Didn't match.
return;
}
}
}
pub fn collect_local_language_items(&mut self) {
let this: *mut LanguageItemCollector = &mut *self;
let mut v = LanguageItemVisitor { this: this };
visit::walk_crate(&mut v, self.crate, ());
pub fn collect_local_language_items(&mut self, crate: &ast::Crate) {
let mut v = LanguageItemVisitor { this: self };
visit::walk_crate(&mut v, crate, ());
}
pub fn collect_external_language_items(&mut self) {
@ -444,24 +416,37 @@ impl<'self> LanguageItemCollector<'self> {
do iter_crate_data(crate_store) |crate_number, _crate_metadata| {
do each_lang_item(crate_store, crate_number)
|node_id, item_index| {
let def_id = DefId { crate: crate_number, node: node_id };
let def_id = ast::DefId { crate: crate_number, node: node_id };
self.collect_item(item_index, def_id);
true
};
}
}
pub fn collect(&mut self) {
self.collect_local_language_items();
pub fn collect(&mut self, crate: &ast::Crate) {
self.collect_local_language_items(crate);
self.collect_external_language_items();
}
}
pub fn collect_language_items(crate: &Crate,
pub fn extract(attrs: &[ast::Attribute]) -> Option<@str> {
for attribute in attrs.iter() {
match attribute.name_str_pair() {
Some((key, value)) if "lang" == key => {
return Some(value);
}
Some(*) | None => {}
}
}
return None;
}
pub fn collect_language_items(crate: &ast::Crate,
session: Session)
-> LanguageItems {
let mut collector = LanguageItemCollector::new(crate, session);
collector.collect();
let mut collector = LanguageItemCollector::new(session);
collector.collect(crate);
let LanguageItemCollector { items, _ } = collector;
session.abort_if_errors();
items

View File

@ -2602,16 +2602,36 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
foreign::register_foreign_item_fn(ccx, abis, &path, ni)
}
ast::foreign_item_static(*) => {
let ident = foreign::link_name(ccx, ni);
unsafe {
let g = do ident.with_c_str |buf| {
let ty = type_of(ccx, ty);
llvm::LLVMAddGlobal(ccx.llmod, ty.to_ref(), buf)
};
if attr::contains_name(ni.attrs, "weak_linkage") {
lib::llvm::SetLinkage(g, lib::llvm::ExternalWeakLinkage);
// Treat the crate map static specially in order to
// a weak-linkage-like functionality where it's
// dynamically resolved at runtime. If we're
// building a library, then we declare the static
// with weak linkage, but if we're building a
// library then we've already declared the crate map
// so use that instead.
if attr::contains_name(ni.attrs, "crate_map") {
if *ccx.sess.building_library {
let s = "_rust_crate_map_toplevel";
let g = unsafe { do s.with_c_str |buf| {
let ty = type_of(ccx, ty);
llvm::LLVMAddGlobal(ccx.llmod,
ty.to_ref(), buf)
} };
lib::llvm::SetLinkage(g,
lib::llvm::ExternalWeakLinkage);
g
} else {
ccx.crate_map
}
} else {
let ident = foreign::link_name(ccx, ni);
unsafe {
do ident.with_c_str |buf| {
let ty = type_of(ccx, ty);
llvm::LLVMAddGlobal(ccx.llmod,
ty.to_ref(), buf)
}
}
g
}
}
}
@ -2937,7 +2957,12 @@ pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta,
let sym_name = ~"_rust_crate_map_" + mapname;
let slicetype = Type::struct_([int_type, int_type], false);
let maptype = Type::struct_([Type::i32(), slicetype, slicetype], false);
let maptype = Type::struct_([
Type::i32(), // version
slicetype, // child modules
slicetype, // sub crate-maps
int_type.ptr_to(), // event loop factory
], false);
let map = do sym_name.with_c_str |buf| {
unsafe {
llvm::LLVMAddGlobal(llmod, maptype.to_ref(), buf)
@ -2972,6 +2997,20 @@ pub fn fill_crate_map(ccx: &mut CrateContext, map: ValueRef) {
subcrates.push(p2i(ccx, cr));
i += 1;
}
let event_loop_factory = if !*ccx.sess.building_library {
match ccx.tcx.lang_items.event_loop_factory() {
Some(did) => unsafe {
let name = csearch::get_symbol(ccx.sess.cstore, did);
let global = do name.with_c_str |buf| {
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf)
};
global
},
None => C_null(ccx.int_type.ptr_to())
}
} else {
C_null(ccx.int_type.ptr_to())
};
unsafe {
let maptype = Type::array(&ccx.int_type, subcrates.len() as u64);
let vec_elements = do "_crate_map_child_vectors".with_c_str |buf| {
@ -2991,7 +3030,8 @@ pub fn fill_crate_map(ccx: &mut CrateContext, map: ValueRef) {
C_struct([
p2i(ccx, vec_elements),
C_uint(ccx, subcrates.len())
], false)
], false),
event_loop_factory,
], false));
}
}

273
src/librustuv/addrinfo.rs Normal file
View File

@ -0,0 +1,273 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::cast::transmute;
use std::cell::Cell;
use std::libc::{c_int, c_void};
use std::ptr::null;
use ai = std::rt::io::net::addrinfo;
use uvll;
use uvll::UV_GETADDRINFO;
use super::{Loop, UvError, NativeHandle, status_to_maybe_uv_error};
use net;
type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &net::UvAddrInfo, Option<UvError>);
pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t);
pub struct RequestData {
priv getaddrinfo_cb: Option<GetAddrInfoCallback>,
}
impl GetAddrInfoRequest {
pub fn new() -> GetAddrInfoRequest {
let req = unsafe { uvll::malloc_req(UV_GETADDRINFO) };
assert!(req.is_not_null());
let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req);
req.install_req_data();
return req;
}
pub fn getaddrinfo(&mut self, loop_: &Loop, node: Option<&str>,
service: Option<&str>, hints: Option<ai::Hint>,
cb: GetAddrInfoCallback) {
assert!(node.is_some() || service.is_some());
let (c_node, c_node_ptr) = match node {
Some(n) => {
let c_node = n.to_c_str();
let c_node_ptr = c_node.with_ref(|r| r);
(Some(c_node), c_node_ptr)
}
None => (None, null())
};
let (c_service, c_service_ptr) = match service {
Some(s) => {
let c_service = s.to_c_str();
let c_service_ptr = c_service.with_ref(|r| r);
(Some(c_service), c_service_ptr)
}
None => (None, null())
};
let cb = Cell::new(cb);
let wrapper_cb: GetAddrInfoCallback = |req, addrinfo, err| {
// Capture some heap values that need to stay alive for the
// getaddrinfo call
let _ = &c_node;
let _ = &c_service;
let cb = cb.take();
cb(req, addrinfo, err)
};
let hint = hints.map(|hint| {
let mut flags = 0;
do each_ai_flag |cval, aival| {
if hint.flags & (aival as uint) != 0 {
flags |= cval as i32;
}
}
/* XXX: do we really want to support these?
let socktype = match hint.socktype {
Some(ai::Stream) => uvll::rust_SOCK_STREAM(),
Some(ai::Datagram) => uvll::rust_SOCK_DGRAM(),
Some(ai::Raw) => uvll::rust_SOCK_RAW(),
None => 0,
};
let protocol = match hint.protocol {
Some(ai::UDP) => uvll::rust_IPPROTO_UDP(),
Some(ai::TCP) => uvll::rust_IPPROTO_TCP(),
_ => 0,
};
*/
let socktype = 0;
let protocol = 0;
uvll::addrinfo {
ai_flags: flags,
ai_family: hint.family as c_int,
ai_socktype: socktype,
ai_protocol: protocol,
ai_addrlen: 0,
ai_canonname: null(),
ai_addr: null(),
ai_next: null(),
}
});
let hint_ptr = hint.as_ref().map_default(null(), |x| x as *uvll::addrinfo);
self.get_req_data().getaddrinfo_cb = Some(wrapper_cb);
unsafe {
assert!(0 == uvll::getaddrinfo(loop_.native_handle(),
self.native_handle(),
getaddrinfo_cb,
c_node_ptr,
c_service_ptr,
hint_ptr));
}
extern "C" fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t,
status: c_int,
res: *uvll::addrinfo) {
let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req);
let err = status_to_maybe_uv_error(status);
let addrinfo = net::UvAddrInfo(res);
let data = req.get_req_data();
(*data.getaddrinfo_cb.get_ref())(req, &addrinfo, err);
unsafe {
uvll::freeaddrinfo(res);
}
}
}
fn get_loop(&self) -> Loop {
unsafe {
Loop {
handle: uvll::get_loop_from_fs_req(self.native_handle())
}
}
}
fn install_req_data(&mut self) {
let req = self.native_handle() as *uvll::uv_getaddrinfo_t;
let data = ~RequestData {
getaddrinfo_cb: None
};
unsafe {
let data = transmute::<~RequestData, *c_void>(data);
uvll::set_data_for_req(req, data);
}
}
fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData {
unsafe {
let data = uvll::get_data_for_req(self.native_handle());
let data = transmute::<&*c_void, &mut ~RequestData>(&data);
return &mut **data;
}
}
fn delete(self) {
unsafe {
let data = uvll::get_data_for_req(self.native_handle());
let _data = transmute::<*c_void, ~RequestData>(data);
uvll::set_data_for_req(self.native_handle(), null::<()>());
uvll::free_req(self.native_handle());
}
}
}
fn each_ai_flag(_f: &fn(c_int, ai::Flag)) {
/* XXX: do we really want to support these?
unsafe {
f(uvll::rust_AI_ADDRCONFIG(), ai::AddrConfig);
f(uvll::rust_AI_ALL(), ai::All);
f(uvll::rust_AI_CANONNAME(), ai::CanonName);
f(uvll::rust_AI_NUMERICHOST(), ai::NumericHost);
f(uvll::rust_AI_NUMERICSERV(), ai::NumericServ);
f(uvll::rust_AI_PASSIVE(), ai::Passive);
f(uvll::rust_AI_V4MAPPED(), ai::V4Mapped);
}
*/
}
// Traverse the addrinfo linked list, producing a vector of Rust socket addresses
pub fn accum_addrinfo(addr: &net::UvAddrInfo) -> ~[ai::Info] {
unsafe {
let &net::UvAddrInfo(addr) = addr;
let mut addr = addr;
let mut addrs = ~[];
loop {
let uvaddr = net::sockaddr_to_UvSocketAddr((*addr).ai_addr);
let rustaddr = net::uv_socket_addr_to_socket_addr(uvaddr);
let mut flags = 0;
do each_ai_flag |cval, aival| {
if (*addr).ai_flags & cval != 0 {
flags |= aival as uint;
}
}
/* XXX: do we really want to support these
let protocol = match (*addr).ai_protocol {
p if p == uvll::rust_IPPROTO_UDP() => Some(ai::UDP),
p if p == uvll::rust_IPPROTO_TCP() => Some(ai::TCP),
_ => None,
};
let socktype = match (*addr).ai_socktype {
p if p == uvll::rust_SOCK_STREAM() => Some(ai::Stream),
p if p == uvll::rust_SOCK_DGRAM() => Some(ai::Datagram),
p if p == uvll::rust_SOCK_RAW() => Some(ai::Raw),
_ => None,
};
*/
let protocol = None;
let socktype = None;
addrs.push(ai::Info {
address: rustaddr,
family: (*addr).ai_family as uint,
socktype: socktype,
protocol: protocol,
flags: flags,
});
if (*addr).ai_next.is_not_null() {
addr = (*addr).ai_next;
} else {
break;
}
}
return addrs;
}
}
impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest {
fn from_native_handle(handle: *uvll::uv_getaddrinfo_t) -> GetAddrInfoRequest {
GetAddrInfoRequest(handle)
}
fn native_handle(&self) -> *uvll::uv_getaddrinfo_t {
match self { &GetAddrInfoRequest(ptr) => ptr }
}
}
#[cfg(test)]
mod test {
use Loop;
use std::rt::io::net::ip::{SocketAddr, Ipv4Addr};
use super::*;
#[test]
fn getaddrinfo_test() {
let mut loop_ = Loop::new();
let mut req = GetAddrInfoRequest::new();
do req.getaddrinfo(&loop_, Some("localhost"), None, None) |_, addrinfo, _| {
let sockaddrs = accum_addrinfo(addrinfo);
let mut found_local = false;
let local_addr = &SocketAddr {
ip: Ipv4Addr(127, 0, 0, 1),
port: 0
};
for addr in sockaddrs.iter() {
found_local = found_local || addr.address == *local_addr;
}
assert!(found_local);
}
loop_.run();
loop_.close();
req.delete();
}
}

83
src/librustuv/async.rs Normal file
View File

@ -0,0 +1,83 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::libc::c_int;
use uvll;
use super::{Watcher, Loop, NativeHandle, AsyncCallback, WatcherInterop};
use super::status_to_maybe_uv_error;
pub struct AsyncWatcher(*uvll::uv_async_t);
impl Watcher for AsyncWatcher { }
impl AsyncWatcher {
pub fn new(loop_: &mut Loop, cb: AsyncCallback) -> AsyncWatcher {
unsafe {
let handle = uvll::malloc_handle(uvll::UV_ASYNC);
assert!(handle.is_not_null());
let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle);
watcher.install_watcher_data();
let data = watcher.get_watcher_data();
data.async_cb = Some(cb);
assert_eq!(0, uvll::async_init(loop_.native_handle(), handle, async_cb));
return watcher;
}
extern fn async_cb(handle: *uvll::uv_async_t, status: c_int) {
let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle);
let status = status_to_maybe_uv_error(status);
let data = watcher.get_watcher_data();
let cb = data.async_cb.get_ref();
(*cb)(watcher, status);
}
}
pub fn send(&mut self) {
unsafe {
let handle = self.native_handle();
uvll::async_send(handle);
}
}
}
impl NativeHandle<*uvll::uv_async_t> for AsyncWatcher {
fn from_native_handle(handle: *uvll::uv_async_t) -> AsyncWatcher {
AsyncWatcher(handle)
}
fn native_handle(&self) -> *uvll::uv_async_t {
match self { &AsyncWatcher(ptr) => ptr }
}
}
#[cfg(test)]
mod test {
use super::*;
use Loop;
use std::unstable::run_in_bare_thread;
use std::rt::thread::Thread;
use std::cell::Cell;
#[test]
fn smoke_test() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let watcher = AsyncWatcher::new(&mut loop_, |w, _| w.close(||()) );
let watcher_cell = Cell::new(watcher);
let thread = do Thread::start {
let mut watcher = watcher_cell.take();
watcher.send();
};
loop_.run();
loop_.close();
thread.join();
}
}
}

647
src/librustuv/file.rs Normal file
View File

@ -0,0 +1,647 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::ptr::null;
use std::c_str;
use std::c_str::CString;
use std::libc::c_void;
use std::cast::transmute;
use std::libc;
use std::libc::{c_int};
use super::{Request, NativeHandle, Loop, FsCallback, Buf,
status_to_maybe_uv_error, UvError};
use uvll;
use uvll::*;
pub struct FsRequest(*uvll::uv_fs_t);
impl Request for FsRequest {}
pub struct RequestData {
priv complete_cb: Option<FsCallback>
}
impl FsRequest {
pub fn new() -> FsRequest {
let fs_req = unsafe { malloc_req(UV_FS) };
assert!(fs_req.is_not_null());
let fs_req: FsRequest = NativeHandle::from_native_handle(fs_req);
fs_req
}
pub fn open(self, loop_: &Loop, path: &CString, flags: int, mode: int,
cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let ret = path.with_ref(|p| unsafe {
uvll::fs_open(loop_.native_handle(),
self.native_handle(), p, flags, mode, complete_cb_ptr)
});
assert_eq!(ret, 0);
}
pub fn open_sync(self, loop_: &Loop, path: &CString,
flags: int, mode: int) -> Result<c_int, UvError> {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(None)
};
let result = path.with_ref(|p| unsafe {
uvll::fs_open(loop_.native_handle(),
self.native_handle(), p, flags, mode, complete_cb_ptr)
});
self.sync_cleanup(result)
}
pub fn unlink(self, loop_: &Loop, path: &CString, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let ret = path.with_ref(|p| unsafe {
uvll::fs_unlink(loop_.native_handle(),
self.native_handle(), p, complete_cb_ptr)
});
assert_eq!(ret, 0);
}
pub fn unlink_sync(self, loop_: &Loop, path: &CString)
-> Result<c_int, UvError> {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(None)
};
let result = path.with_ref(|p| unsafe {
uvll::fs_unlink(loop_.native_handle(),
self.native_handle(), p, complete_cb_ptr)
});
self.sync_cleanup(result)
}
pub fn stat(self, loop_: &Loop, path: &CString, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let ret = path.with_ref(|p| unsafe {
uvll::fs_stat(loop_.native_handle(),
self.native_handle(), p, complete_cb_ptr)
});
assert_eq!(ret, 0);
}
pub fn write(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let base_ptr = buf.base as *c_void;
let len = buf.len as uint;
let ret = unsafe {
uvll::fs_write(loop_.native_handle(), self.native_handle(),
fd, base_ptr,
len, offset, complete_cb_ptr)
};
assert_eq!(ret, 0);
}
pub fn write_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64)
-> Result<c_int, UvError> {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(None)
};
let base_ptr = buf.base as *c_void;
let len = buf.len as uint;
let result = unsafe {
uvll::fs_write(loop_.native_handle(), self.native_handle(),
fd, base_ptr,
len, offset, complete_cb_ptr)
};
self.sync_cleanup(result)
}
pub fn read(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let buf_ptr = buf.base as *c_void;
let len = buf.len as uint;
let ret = unsafe {
uvll::fs_read(loop_.native_handle(), self.native_handle(),
fd, buf_ptr,
len, offset, complete_cb_ptr)
};
assert_eq!(ret, 0);
}
pub fn read_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64)
-> Result<c_int, UvError> {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(None)
};
let buf_ptr = buf.base as *c_void;
let len = buf.len as uint;
let result = unsafe {
uvll::fs_read(loop_.native_handle(), self.native_handle(),
fd, buf_ptr,
len, offset, complete_cb_ptr)
};
self.sync_cleanup(result)
}
pub fn close(self, loop_: &Loop, fd: c_int, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let ret = unsafe {
uvll::fs_close(loop_.native_handle(), self.native_handle(),
fd, complete_cb_ptr)
};
assert_eq!(ret, 0);
}
pub fn close_sync(self, loop_: &Loop, fd: c_int) -> Result<c_int, UvError> {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(None)
};
let result = unsafe {
uvll::fs_close(loop_.native_handle(), self.native_handle(),
fd, complete_cb_ptr)
};
self.sync_cleanup(result)
}
pub fn mkdir(self, loop_: &Loop, path: &CString, mode: int, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let ret = path.with_ref(|p| unsafe {
uvll::fs_mkdir(loop_.native_handle(),
self.native_handle(), p, mode, complete_cb_ptr)
});
assert_eq!(ret, 0);
}
pub fn rmdir(self, loop_: &Loop, path: &CString, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let ret = path.with_ref(|p| unsafe {
uvll::fs_rmdir(loop_.native_handle(),
self.native_handle(), p, complete_cb_ptr)
});
assert_eq!(ret, 0);
}
pub fn readdir(self, loop_: &Loop, path: &CString,
flags: c_int, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let ret = path.with_ref(|p| unsafe {
uvll::fs_readdir(loop_.native_handle(),
self.native_handle(), p, flags, complete_cb_ptr)
});
assert_eq!(ret, 0);
}
// accessors/utility funcs
fn sync_cleanup(self, result: c_int)
-> Result<c_int, UvError> {
self.cleanup_and_delete();
match status_to_maybe_uv_error(result as i32) {
Some(err) => Err(err),
None => Ok(result)
}
}
fn req_boilerplate(&mut self, cb: Option<FsCallback>) -> *u8 {
let result = match cb {
Some(_) => {
compl_cb as *u8
},
None => 0 as *u8
};
self.install_req_data(cb);
result
}
pub fn install_req_data(&mut self, cb: Option<FsCallback>) {
let fs_req = (self.native_handle()) as *uvll::uv_write_t;
let data = ~RequestData {
complete_cb: cb
};
unsafe {
let data = transmute::<~RequestData, *c_void>(data);
uvll::set_data_for_req(fs_req, data);
}
}
fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData {
unsafe {
let data = uvll::get_data_for_req((self.native_handle()));
let data = transmute::<&*c_void, &mut ~RequestData>(&data);
&mut **data
}
}
pub fn get_result(&mut self) -> c_int {
unsafe {
uvll::get_result_from_fs_req(self.native_handle())
}
}
pub fn get_loop(&self) -> Loop {
unsafe { Loop{handle:uvll::get_loop_from_fs_req(self.native_handle())} }
}
pub fn get_stat(&self) -> uv_stat_t {
let stat = uv_stat_t::new();
unsafe { uvll::populate_stat(self.native_handle(), &stat); }
stat
}
pub fn get_ptr(&self) -> *libc::c_void {
unsafe {
uvll::get_ptr_from_fs_req(self.native_handle())
}
}
pub fn each_path(&mut self, f: &fn(&CString)) {
let ptr = self.get_ptr();
match self.get_result() {
n if (n <= 0) => {}
n => {
let n_len = n as uint;
// we pass in the len that uv tells us is there
// for the entries and we don't continue past that..
// it appears that sometimes the multistring isn't
// correctly delimited and we stray into garbage memory?
// in any case, passing Some(n_len) fixes it and ensures
// good results
unsafe {
c_str::from_c_multistring(ptr as *libc::c_char,
Some(n_len), f);
}
}
}
}
fn cleanup_and_delete(self) {
unsafe {
let data = uvll::get_data_for_req(self.native_handle());
let _data = transmute::<*c_void, ~RequestData>(data);
uvll::set_data_for_req(self.native_handle(), null::<()>());
uvll::fs_req_cleanup(self.native_handle());
free_req(self.native_handle() as *c_void)
}
}
}
impl NativeHandle<*uvll::uv_fs_t> for FsRequest {
fn from_native_handle(handle: *uvll:: uv_fs_t) -> FsRequest {
FsRequest(handle)
}
fn native_handle(&self) -> *uvll::uv_fs_t {
match self { &FsRequest(ptr) => ptr }
}
}
fn sync_cleanup(result: int)
-> Result<int, UvError> {
match status_to_maybe_uv_error(result as i32) {
Some(err) => Err(err),
None => Ok(result)
}
}
extern fn compl_cb(req: *uv_fs_t) {
let mut req: FsRequest = NativeHandle::from_native_handle(req);
// pull the user cb out of the req data
let cb = {
let data = req.get_req_data();
assert!(data.complete_cb.is_some());
// option dance, option dance. oooooh yeah.
data.complete_cb.take_unwrap()
};
// in uv_fs_open calls, the result will be the fd in the
// case of success, otherwise it's -1 indicating an error
let result = req.get_result();
let status = status_to_maybe_uv_error(result);
// we have a req and status, call the user cb..
// only giving the user a ref to the FsRequest, as we
// have to clean it up, afterwards (and they aren't really
// reusable, anyways
cb(&mut req, status);
// clean up the req (and its data!) after calling the user cb
req.cleanup_and_delete();
}
#[cfg(test)]
mod test {
use super::*;
//use std::rt::test::*;
use std::libc::{STDOUT_FILENO};
use std::vec;
use std::str;
use std::unstable::run_in_bare_thread;
use super::super::{Loop, Buf, slice_to_uv_buf};
use std::libc::{O_CREAT, O_RDWR, O_RDONLY, S_IWUSR, S_IRUSR};
#[test]
fn file_test_full_simple() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let create_flags = O_RDWR | O_CREAT;
let read_flags = O_RDONLY;
// 0644 BZZT! WRONG! 0600! See below.
let mode = S_IWUSR |S_IRUSR;
// these aren't defined in std::libc :(
//map_mode(S_IRGRP) |
//map_mode(S_IROTH);
let path_str = "./tmp/file_full_simple.txt";
let write_val = "hello".as_bytes().to_owned();
let write_buf = slice_to_uv_buf(write_val);
let write_buf_ptr: *Buf = &write_buf;
let read_buf_len = 1028;
let read_mem = vec::from_elem(read_buf_len, 0u8);
let read_buf = slice_to_uv_buf(read_mem);
let read_buf_ptr: *Buf = &read_buf;
let open_req = FsRequest::new();
do open_req.open(&loop_, &path_str.to_c_str(), create_flags as int,
mode as int) |req, uverr| {
assert!(uverr.is_none());
let fd = req.get_result();
let buf = unsafe { *write_buf_ptr };
let write_req = FsRequest::new();
do write_req.write(&req.get_loop(), fd, buf, -1) |req, uverr| {
let close_req = FsRequest::new();
do close_req.close(&req.get_loop(), fd) |req, _| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let open_req = FsRequest::new();
do open_req.open(&loop_, &path_str.to_c_str(),
read_flags as int,0) |req, uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let fd = req.get_result();
let read_buf = unsafe { *read_buf_ptr };
let read_req = FsRequest::new();
do read_req.read(&loop_, fd, read_buf, 0) |req, uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
// we know nread >=0 because uverr is none..
let nread = req.get_result() as uint;
// nread == 0 would be EOF
if nread > 0 {
let read_str = unsafe {
let read_buf = *read_buf_ptr;
str::from_utf8(
vec::from_buf(
read_buf.base, nread))
};
assert!(read_str == ~"hello");
let close_req = FsRequest::new();
do close_req.close(&loop_, fd) |req,uverr| {
assert!(uverr.is_none());
let loop_ = &req.get_loop();
let unlink_req = FsRequest::new();
do unlink_req.unlink(loop_,
&path_str.to_c_str())
|_,uverr| {
assert!(uverr.is_none());
};
};
};
};
};
};
};
};
loop_.run();
loop_.close();
}
}
#[test]
fn file_test_full_simple_sync() {
do run_in_bare_thread {
// setup
let mut loop_ = Loop::new();
let create_flags = O_RDWR |
O_CREAT;
let read_flags = O_RDONLY;
// 0644
let mode = S_IWUSR |
S_IRUSR;
//S_IRGRP |
//S_IROTH;
let path_str = "./tmp/file_full_simple_sync.txt";
let write_val = "hello".as_bytes().to_owned();
let write_buf = slice_to_uv_buf(write_val);
// open/create
let open_req = FsRequest::new();
let result = open_req.open_sync(&loop_, &path_str.to_c_str(),
create_flags as int, mode as int);
assert!(result.is_ok());
let fd = result.unwrap();
// write
let write_req = FsRequest::new();
let result = write_req.write_sync(&loop_, fd, write_buf, -1);
assert!(result.is_ok());
// close
let close_req = FsRequest::new();
let result = close_req.close_sync(&loop_, fd);
assert!(result.is_ok());
// re-open
let open_req = FsRequest::new();
let result = open_req.open_sync(&loop_, &path_str.to_c_str(),
read_flags as int,0);
assert!(result.is_ok());
let len = 1028;
let fd = result.unwrap();
// read
let read_mem: ~[u8] = vec::from_elem(len, 0u8);
let buf = slice_to_uv_buf(read_mem);
let read_req = FsRequest::new();
let result = read_req.read_sync(&loop_, fd, buf, 0);
assert!(result.is_ok());
let nread = result.unwrap();
// nread == 0 would be EOF.. we know it's >= zero because otherwise
// the above assert would fail
if nread > 0 {
let read_str = str::from_utf8(
read_mem.slice(0, nread as uint));
assert!(read_str == ~"hello");
// close
let close_req = FsRequest::new();
let result = close_req.close_sync(&loop_, fd);
assert!(result.is_ok());
// unlink
let unlink_req = FsRequest::new();
let result = unlink_req.unlink_sync(&loop_, &path_str.to_c_str());
assert!(result.is_ok());
} else { fail!("nread was 0.. wudn't expectin' that."); }
loop_.close();
}
}
fn naive_print(loop_: &Loop, input: &str) {
let write_val = input.as_bytes();
let write_buf = slice_to_uv_buf(write_val);
let write_req = FsRequest::new();
write_req.write_sync(loop_, STDOUT_FILENO, write_buf, -1);
}
#[test]
fn file_test_write_to_stdout() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
naive_print(&loop_, "zanzibar!\n");
loop_.run();
loop_.close();
};
}
#[test]
fn file_test_stat_simple() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let path = "./tmp/file_test_stat_simple.txt";
let create_flags = O_RDWR |
O_CREAT;
let mode = S_IWUSR |
S_IRUSR;
let write_val = "hello".as_bytes().to_owned();
let write_buf = slice_to_uv_buf(write_val);
let write_buf_ptr: *Buf = &write_buf;
let open_req = FsRequest::new();
do open_req.open(&loop_, &path.to_c_str(), create_flags as int,
mode as int) |req, uverr| {
assert!(uverr.is_none());
let fd = req.get_result();
let buf = unsafe { *write_buf_ptr };
let write_req = FsRequest::new();
do write_req.write(&req.get_loop(), fd, buf, 0) |req, uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let stat_req = FsRequest::new();
do stat_req.stat(&loop_, &path.to_c_str()) |req, uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let stat = req.get_stat();
let sz: uint = stat.st_size as uint;
assert!(sz > 0);
let close_req = FsRequest::new();
do close_req.close(&loop_, fd) |req, uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let unlink_req = FsRequest::new();
do unlink_req.unlink(&loop_,
&path.to_c_str()) |req,uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let stat_req = FsRequest::new();
do stat_req.stat(&loop_,
&path.to_c_str()) |_, uverr| {
// should cause an error because the
// file doesn't exist anymore
assert!(uverr.is_some());
};
};
};
};
};
};
loop_.run();
loop_.close();
}
}
#[test]
fn file_test_mk_rm_dir() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let path = "./tmp/mk_rm_dir";
let mode = S_IWUSR |
S_IRUSR;
let mkdir_req = FsRequest::new();
do mkdir_req.mkdir(&loop_, &path.to_c_str(),
mode as int) |req,uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let stat_req = FsRequest::new();
do stat_req.stat(&loop_, &path.to_c_str()) |req, uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let stat = req.get_stat();
naive_print(&loop_, format!("{:?}", stat));
assert!(stat.is_dir());
let rmdir_req = FsRequest::new();
do rmdir_req.rmdir(&loop_, &path.to_c_str()) |req,uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let stat_req = FsRequest::new();
do stat_req.stat(&loop_, &path.to_c_str()) |_req, uverr| {
assert!(uverr.is_some());
}
}
}
}
loop_.run();
loop_.close();
}
}
#[test]
fn file_test_mkdir_chokes_on_double_create() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let path = "./tmp/double_create_dir";
let mode = S_IWUSR |
S_IRUSR;
let mkdir_req = FsRequest::new();
do mkdir_req.mkdir(&loop_, &path.to_c_str(), mode as int) |req,uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let mkdir_req = FsRequest::new();
do mkdir_req.mkdir(&loop_, &path.to_c_str(),
mode as int) |req,uverr| {
assert!(uverr.is_some());
let loop_ = req.get_loop();
let _stat = req.get_stat();
let rmdir_req = FsRequest::new();
do rmdir_req.rmdir(&loop_, &path.to_c_str()) |req,uverr| {
assert!(uverr.is_none());
let _loop = req.get_loop();
}
}
}
loop_.run();
loop_.close();
}
}
#[test]
fn file_test_rmdir_chokes_on_nonexistant_path() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let path = "./tmp/never_existed_dir";
let rmdir_req = FsRequest::new();
do rmdir_req.rmdir(&loop_, &path.to_c_str()) |_req, uverr| {
assert!(uverr.is_some());
}
loop_.run();
loop_.close();
}
}
}

137
src/librustuv/idle.rs Normal file
View File

@ -0,0 +1,137 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::libc::c_int;
use uvll;
use super::{Watcher, Loop, NativeHandle, IdleCallback, status_to_maybe_uv_error};
pub struct IdleWatcher(*uvll::uv_idle_t);
impl Watcher for IdleWatcher { }
impl IdleWatcher {
pub fn new(loop_: &mut Loop) -> IdleWatcher {
unsafe {
let handle = uvll::malloc_handle(uvll::UV_IDLE);
assert!(handle.is_not_null());
assert_eq!(uvll::idle_init(loop_.native_handle(), handle), 0);
let mut watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
watcher.install_watcher_data();
return watcher
}
}
pub fn start(&mut self, cb: IdleCallback) {
{
let data = self.get_watcher_data();
data.idle_cb = Some(cb);
}
unsafe {
assert_eq!(uvll::idle_start(self.native_handle(), idle_cb), 0)
}
}
pub fn restart(&mut self) {
unsafe {
assert!(self.get_watcher_data().idle_cb.is_some());
assert_eq!(uvll::idle_start(self.native_handle(), idle_cb), 0)
}
}
pub fn stop(&mut self) {
// NB: Not resetting the Rust idle_cb to None here because `stop` is
// likely called from *within* the idle callback, causing a use after
// free
unsafe {
assert_eq!(uvll::idle_stop(self.native_handle()), 0);
}
}
}
impl NativeHandle<*uvll::uv_idle_t> for IdleWatcher {
fn from_native_handle(handle: *uvll::uv_idle_t) -> IdleWatcher {
IdleWatcher(handle)
}
fn native_handle(&self) -> *uvll::uv_idle_t {
match self { &IdleWatcher(ptr) => ptr }
}
}
extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) {
let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
let data = idle_watcher.get_watcher_data();
let cb: &IdleCallback = data.idle_cb.get_ref();
let status = status_to_maybe_uv_error(status);
(*cb)(idle_watcher, status);
}
#[cfg(test)]
mod test {
use Loop;
use super::*;
use std::unstable::run_in_bare_thread;
#[test]
#[ignore(reason = "valgrind - loop destroyed before watcher?")]
fn idle_new_then_close() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let idle_watcher = { IdleWatcher::new(&mut loop_) };
idle_watcher.close(||());
}
}
#[test]
fn idle_smoke_test() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let mut idle_watcher = { IdleWatcher::new(&mut loop_) };
let mut count = 10;
let count_ptr: *mut int = &mut count;
do idle_watcher.start |idle_watcher, status| {
let mut idle_watcher = idle_watcher;
assert!(status.is_none());
if unsafe { *count_ptr == 10 } {
idle_watcher.stop();
idle_watcher.close(||());
} else {
unsafe { *count_ptr = *count_ptr + 1; }
}
}
loop_.run();
loop_.close();
assert_eq!(count, 10);
}
}
#[test]
fn idle_start_stop_start() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let mut idle_watcher = { IdleWatcher::new(&mut loop_) };
do idle_watcher.start |idle_watcher, status| {
let mut idle_watcher = idle_watcher;
assert!(status.is_none());
idle_watcher.stop();
do idle_watcher.start |idle_watcher, status| {
assert!(status.is_none());
let mut idle_watcher = idle_watcher;
idle_watcher.stop();
idle_watcher.close(||());
}
}
loop_.run();
loop_.close();
}
}
}

36
src/librustuv/macros.rs Normal file
View File

@ -0,0 +1,36 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_escape];
use std::fmt;
macro_rules! uverrln (
($($arg:tt)*) => ( {
format_args!(::macros::dumb_println, $($arg)*)
} )
)
// Some basic logging. Enabled by passing `--cfg uvdebug` to the libstd build.
macro_rules! uvdebug (
($($arg:tt)*) => ( {
if cfg!(uvdebug) {
uverrln!($($arg)*)
}
})
)
pub fn dumb_println(args: &fmt::Arguments) {
use std::rt::io::native::stdio::stderr;
use std::rt::io::Writer;
let mut out = stderr();
fmt::writeln(&mut out as &mut Writer, args);
}

851
src/librustuv/net.rs Normal file
View File

@ -0,0 +1,851 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::libc::{size_t, ssize_t, c_int, c_void, c_uint};
use std::vec;
use std::str;
use std::rt::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr};
use uvll;
use uvll::*;
use super::{AllocCallback, ConnectionCallback, ReadCallback, UdpReceiveCallback,
UdpSendCallback, Loop, Watcher, Request, UvError, Buf, NativeHandle,
status_to_maybe_uv_error, empty_buf};
pub struct UvAddrInfo(*uvll::addrinfo);
pub enum UvSocketAddr {
UvIpv4SocketAddr(*sockaddr_in),
UvIpv6SocketAddr(*sockaddr_in6),
}
pub fn sockaddr_to_UvSocketAddr(addr: *uvll::sockaddr) -> UvSocketAddr {
unsafe {
assert!((is_ip4_addr(addr) || is_ip6_addr(addr)));
assert!(!(is_ip4_addr(addr) && is_ip6_addr(addr)));
match addr {
_ if is_ip4_addr(addr) => UvIpv4SocketAddr(addr as *uvll::sockaddr_in),
_ if is_ip6_addr(addr) => UvIpv6SocketAddr(addr as *uvll::sockaddr_in6),
_ => fail!(),
}
}
}
fn socket_addr_as_uv_socket_addr<T>(addr: SocketAddr, f: &fn(UvSocketAddr) -> T) -> T {
let malloc = match addr.ip {
Ipv4Addr(*) => malloc_ip4_addr,
Ipv6Addr(*) => malloc_ip6_addr,
};
let wrap = match addr.ip {
Ipv4Addr(*) => UvIpv4SocketAddr,
Ipv6Addr(*) => UvIpv6SocketAddr,
};
let free = match addr.ip {
Ipv4Addr(*) => free_ip4_addr,
Ipv6Addr(*) => free_ip6_addr,
};
let addr = unsafe { malloc(addr.ip.to_str(), addr.port as int) };
do (|| {
f(wrap(addr))
}).finally {
unsafe { free(addr) };
}
}
fn uv_socket_addr_as_socket_addr<T>(addr: UvSocketAddr, f: &fn(SocketAddr) -> T) -> T {
let ip_size = match addr {
UvIpv4SocketAddr(*) => 4/*groups of*/ * 3/*digits separated by*/ + 3/*periods*/,
UvIpv6SocketAddr(*) => 8/*groups of*/ * 4/*hex digits separated by*/ + 7 /*colons*/,
};
let ip_name = {
let buf = vec::from_elem(ip_size + 1 /*null terminated*/, 0u8);
unsafe {
let buf_ptr = vec::raw::to_ptr(buf);
match addr {
UvIpv4SocketAddr(addr) => uvll::ip4_name(addr, buf_ptr, ip_size as size_t),
UvIpv6SocketAddr(addr) => uvll::ip6_name(addr, buf_ptr, ip_size as size_t),
}
};
buf
};
let ip_port = unsafe {
let port = match addr {
UvIpv4SocketAddr(addr) => uvll::ip4_port(addr),
UvIpv6SocketAddr(addr) => uvll::ip6_port(addr),
};
port as u16
};
let ip_str = str::from_utf8_slice(ip_name).trim_right_chars(&'\x00');
let ip_addr = FromStr::from_str(ip_str).unwrap();
// finally run the closure
f(SocketAddr { ip: ip_addr, port: ip_port })
}
pub fn uv_socket_addr_to_socket_addr(addr: UvSocketAddr) -> SocketAddr {
use std::util;
uv_socket_addr_as_socket_addr(addr, util::id)
}
#[cfg(test)]
#[test]
fn test_ip4_conversion() {
use std::rt;
let ip4 = rt::test::next_test_ip4();
assert_eq!(ip4, socket_addr_as_uv_socket_addr(ip4, uv_socket_addr_to_socket_addr));
}
#[cfg(test)]
#[test]
fn test_ip6_conversion() {
use std::rt;
let ip6 = rt::test::next_test_ip6();
assert_eq!(ip6, socket_addr_as_uv_socket_addr(ip6, uv_socket_addr_to_socket_addr));
}
// uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t, uv_tty_t
// and uv_file_t
pub struct StreamWatcher(*uvll::uv_stream_t);
impl Watcher for StreamWatcher { }
impl StreamWatcher {
pub fn read_start(&mut self, alloc: AllocCallback, cb: ReadCallback) {
unsafe {
match uvll::read_start(self.native_handle(), alloc_cb, read_cb) {
0 => {
let data = self.get_watcher_data();
data.alloc_cb = Some(alloc);
data.read_cb = Some(cb);
}
n => {
cb(*self, 0, empty_buf(), Some(UvError(n)))
}
}
}
extern fn alloc_cb(stream: *uvll::uv_stream_t, suggested_size: size_t) -> Buf {
let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream);
let alloc_cb = stream_watcher.get_watcher_data().alloc_cb.get_ref();
return (*alloc_cb)(suggested_size as uint);
}
extern fn read_cb(stream: *uvll::uv_stream_t, nread: ssize_t, buf: Buf) {
uvdebug!("buf addr: {}", buf.base);
uvdebug!("buf len: {}", buf.len);
let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream);
let cb = stream_watcher.get_watcher_data().read_cb.get_ref();
let status = status_to_maybe_uv_error(nread as c_int);
(*cb)(stream_watcher, nread as int, buf, status);
}
}
pub fn read_stop(&mut self) {
// It would be nice to drop the alloc and read callbacks here,
// but read_stop may be called from inside one of them and we
// would end up freeing the in-use environment
let handle = self.native_handle();
unsafe { assert_eq!(uvll::read_stop(handle), 0); }
}
pub fn write(&mut self, buf: Buf, cb: ConnectionCallback) {
let req = WriteRequest::new();
return unsafe {
match uvll::write(req.native_handle(), self.native_handle(),
[buf], write_cb) {
0 => {
let data = self.get_watcher_data();
assert!(data.write_cb.is_none());
data.write_cb = Some(cb);
}
n => {
req.delete();
cb(*self, Some(UvError(n)))
}
}
};
extern fn write_cb(req: *uvll::uv_write_t, status: c_int) {
let write_request: WriteRequest = NativeHandle::from_native_handle(req);
let mut stream_watcher = write_request.stream();
write_request.delete();
let cb = stream_watcher.get_watcher_data().write_cb.take_unwrap();
let status = status_to_maybe_uv_error(status);
cb(stream_watcher, status);
}
}
pub fn listen(&mut self, cb: ConnectionCallback) -> Result<(), UvError> {
{
let data = self.get_watcher_data();
assert!(data.connect_cb.is_none());
data.connect_cb = Some(cb);
}
return unsafe {
static BACKLOG: c_int = 128; // XXX should be configurable
match uvll::listen(self.native_handle(), BACKLOG, connection_cb) {
0 => Ok(()),
n => Err(UvError(n))
}
};
extern fn connection_cb(handle: *uvll::uv_stream_t, status: c_int) {
uvdebug!("connection_cb");
let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle);
let cb = stream_watcher.get_watcher_data().connect_cb.get_ref();
let status = status_to_maybe_uv_error(status);
(*cb)(stream_watcher, status);
}
}
pub fn accept(&mut self, stream: StreamWatcher) {
let self_handle = self.native_handle() as *c_void;
let stream_handle = stream.native_handle() as *c_void;
assert_eq!(0, unsafe { uvll::accept(self_handle, stream_handle) } );
}
}
impl NativeHandle<*uvll::uv_stream_t> for StreamWatcher {
fn from_native_handle(handle: *uvll::uv_stream_t) -> StreamWatcher {
StreamWatcher(handle)
}
fn native_handle(&self) -> *uvll::uv_stream_t {
match self { &StreamWatcher(ptr) => ptr }
}
}
pub struct TcpWatcher(*uvll::uv_tcp_t);
impl Watcher for TcpWatcher { }
impl TcpWatcher {
pub fn new(loop_: &Loop) -> TcpWatcher {
unsafe {
let handle = malloc_handle(UV_TCP);
assert!(handle.is_not_null());
assert_eq!(0, uvll::tcp_init(loop_.native_handle(), handle));
let mut watcher: TcpWatcher = NativeHandle::from_native_handle(handle);
watcher.install_watcher_data();
return watcher;
}
}
pub fn bind(&mut self, address: SocketAddr) -> Result<(), UvError> {
do socket_addr_as_uv_socket_addr(address) |addr| {
let result = unsafe {
match addr {
UvIpv4SocketAddr(addr) => uvll::tcp_bind(self.native_handle(), addr),
UvIpv6SocketAddr(addr) => uvll::tcp_bind6(self.native_handle(), addr),
}
};
match result {
0 => Ok(()),
_ => Err(UvError(result)),
}
}
}
pub fn connect(&mut self, address: SocketAddr, cb: ConnectionCallback) {
unsafe {
assert!(self.get_watcher_data().connect_cb.is_none());
self.get_watcher_data().connect_cb = Some(cb);
let connect_handle = ConnectRequest::new().native_handle();
uvdebug!("connect_t: {}", connect_handle);
do socket_addr_as_uv_socket_addr(address) |addr| {
let result = match addr {
UvIpv4SocketAddr(addr) => uvll::tcp_connect(connect_handle,
self.native_handle(), addr, connect_cb),
UvIpv6SocketAddr(addr) => uvll::tcp_connect6(connect_handle,
self.native_handle(), addr, connect_cb),
};
assert_eq!(0, result);
}
extern fn connect_cb(req: *uvll::uv_connect_t, status: c_int) {
uvdebug!("connect_t: {}", req);
let connect_request: ConnectRequest = NativeHandle::from_native_handle(req);
let mut stream_watcher = connect_request.stream();
connect_request.delete();
let cb = stream_watcher.get_watcher_data().connect_cb.take_unwrap();
let status = status_to_maybe_uv_error(status);
cb(stream_watcher, status);
}
}
}
pub fn as_stream(&self) -> StreamWatcher {
NativeHandle::from_native_handle(self.native_handle() as *uvll::uv_stream_t)
}
}
impl NativeHandle<*uvll::uv_tcp_t> for TcpWatcher {
fn from_native_handle(handle: *uvll::uv_tcp_t) -> TcpWatcher {
TcpWatcher(handle)
}
fn native_handle(&self) -> *uvll::uv_tcp_t {
match self { &TcpWatcher(ptr) => ptr }
}
}
pub struct UdpWatcher(*uvll::uv_udp_t);
impl Watcher for UdpWatcher { }
impl UdpWatcher {
pub fn new(loop_: &Loop) -> UdpWatcher {
unsafe {
let handle = malloc_handle(UV_UDP);
assert!(handle.is_not_null());
assert_eq!(0, uvll::udp_init(loop_.native_handle(), handle));
let mut watcher: UdpWatcher = NativeHandle::from_native_handle(handle);
watcher.install_watcher_data();
return watcher;
}
}
pub fn bind(&mut self, address: SocketAddr) -> Result<(), UvError> {
do socket_addr_as_uv_socket_addr(address) |addr| {
let result = unsafe {
match addr {
UvIpv4SocketAddr(addr) => uvll::udp_bind(self.native_handle(), addr, 0u32),
UvIpv6SocketAddr(addr) => uvll::udp_bind6(self.native_handle(), addr, 0u32),
}
};
match result {
0 => Ok(()),
_ => Err(UvError(result)),
}
}
}
pub fn recv_start(&mut self, alloc: AllocCallback, cb: UdpReceiveCallback) {
{
let data = self.get_watcher_data();
data.alloc_cb = Some(alloc);
data.udp_recv_cb = Some(cb);
}
unsafe { uvll::udp_recv_start(self.native_handle(), alloc_cb, recv_cb); }
extern fn alloc_cb(handle: *uvll::uv_udp_t, suggested_size: size_t) -> Buf {
let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle);
let alloc_cb = udp_watcher.get_watcher_data().alloc_cb.get_ref();
return (*alloc_cb)(suggested_size as uint);
}
extern fn recv_cb(handle: *uvll::uv_udp_t, nread: ssize_t, buf: Buf,
addr: *uvll::sockaddr, flags: c_uint) {
// When there's no data to read the recv callback can be a no-op.
// This can happen if read returns EAGAIN/EWOULDBLOCK. By ignoring
// this we just drop back to kqueue and wait for the next callback.
if nread == 0 {
return;
}
uvdebug!("buf addr: {}", buf.base);
uvdebug!("buf len: {}", buf.len);
let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle);
let cb = udp_watcher.get_watcher_data().udp_recv_cb.get_ref();
let status = status_to_maybe_uv_error(nread as c_int);
let addr = uv_socket_addr_to_socket_addr(sockaddr_to_UvSocketAddr(addr));
(*cb)(udp_watcher, nread as int, buf, addr, flags as uint, status);
}
}
pub fn recv_stop(&mut self) {
unsafe { uvll::udp_recv_stop(self.native_handle()); }
}
pub fn send(&mut self, buf: Buf, address: SocketAddr, cb: UdpSendCallback) {
{
let data = self.get_watcher_data();
assert!(data.udp_send_cb.is_none());
data.udp_send_cb = Some(cb);
}
let req = UdpSendRequest::new();
do socket_addr_as_uv_socket_addr(address) |addr| {
let result = unsafe {
match addr {
UvIpv4SocketAddr(addr) => uvll::udp_send(req.native_handle(),
self.native_handle(), [buf], addr, send_cb),
UvIpv6SocketAddr(addr) => uvll::udp_send6(req.native_handle(),
self.native_handle(), [buf], addr, send_cb),
}
};
assert_eq!(0, result);
}
extern fn send_cb(req: *uvll::uv_udp_send_t, status: c_int) {
let send_request: UdpSendRequest = NativeHandle::from_native_handle(req);
let mut udp_watcher = send_request.handle();
send_request.delete();
let cb = udp_watcher.get_watcher_data().udp_send_cb.take_unwrap();
let status = status_to_maybe_uv_error(status);
cb(udp_watcher, status);
}
}
}
impl NativeHandle<*uvll::uv_udp_t> for UdpWatcher {
fn from_native_handle(handle: *uvll::uv_udp_t) -> UdpWatcher {
UdpWatcher(handle)
}
fn native_handle(&self) -> *uvll::uv_udp_t {
match self { &UdpWatcher(ptr) => ptr }
}
}
// uv_connect_t is a subclass of uv_req_t
pub struct ConnectRequest(*uvll::uv_connect_t);
impl Request for ConnectRequest { }
impl ConnectRequest {
pub fn new() -> ConnectRequest {
let connect_handle = unsafe { malloc_req(UV_CONNECT) };
assert!(connect_handle.is_not_null());
ConnectRequest(connect_handle as *uvll::uv_connect_t)
}
fn stream(&self) -> StreamWatcher {
unsafe {
let stream_handle = uvll::get_stream_handle_from_connect_req(self.native_handle());
NativeHandle::from_native_handle(stream_handle)
}
}
fn delete(self) {
unsafe { free_req(self.native_handle() as *c_void) }
}
}
impl NativeHandle<*uvll::uv_connect_t> for ConnectRequest {
fn from_native_handle(handle: *uvll:: uv_connect_t) -> ConnectRequest {
ConnectRequest(handle)
}
fn native_handle(&self) -> *uvll::uv_connect_t {
match self { &ConnectRequest(ptr) => ptr }
}
}
pub struct WriteRequest(*uvll::uv_write_t);
impl Request for WriteRequest { }
impl WriteRequest {
pub fn new() -> WriteRequest {
let write_handle = unsafe { malloc_req(UV_WRITE) };
assert!(write_handle.is_not_null());
WriteRequest(write_handle as *uvll::uv_write_t)
}
pub fn stream(&self) -> StreamWatcher {
unsafe {
let stream_handle = uvll::get_stream_handle_from_write_req(self.native_handle());
NativeHandle::from_native_handle(stream_handle)
}
}
pub fn delete(self) {
unsafe { free_req(self.native_handle() as *c_void) }
}
}
impl NativeHandle<*uvll::uv_write_t> for WriteRequest {
fn from_native_handle(handle: *uvll:: uv_write_t) -> WriteRequest {
WriteRequest(handle)
}
fn native_handle(&self) -> *uvll::uv_write_t {
match self { &WriteRequest(ptr) => ptr }
}
}
pub struct UdpSendRequest(*uvll::uv_udp_send_t);
impl Request for UdpSendRequest { }
impl UdpSendRequest {
pub fn new() -> UdpSendRequest {
let send_handle = unsafe { malloc_req(UV_UDP_SEND) };
assert!(send_handle.is_not_null());
UdpSendRequest(send_handle as *uvll::uv_udp_send_t)
}
pub fn handle(&self) -> UdpWatcher {
let send_request_handle = unsafe {
uvll::get_udp_handle_from_send_req(self.native_handle())
};
NativeHandle::from_native_handle(send_request_handle)
}
pub fn delete(self) {
unsafe { free_req(self.native_handle() as *c_void) }
}
}
impl NativeHandle<*uvll::uv_udp_send_t> for UdpSendRequest {
fn from_native_handle(handle: *uvll::uv_udp_send_t) -> UdpSendRequest {
UdpSendRequest(handle)
}
fn native_handle(&self) -> *uvll::uv_udp_send_t {
match self { &UdpSendRequest(ptr) => ptr }
}
}
#[cfg(test)]
mod test {
use super::*;
use std::util::ignore;
use std::cell::Cell;
use std::vec;
use std::unstable::run_in_bare_thread;
use std::rt::thread::Thread;
use std::rt::test::*;
use super::super::{Loop, AllocCallback};
use super::super::{vec_from_uv_buf, vec_to_uv_buf, slice_to_uv_buf};
#[test]
fn connect_close_ip4() {
do run_in_bare_thread() {
let mut loop_ = Loop::new();
let mut tcp_watcher = { TcpWatcher::new(&mut loop_) };
// Connect to a port where nobody is listening
let addr = next_test_ip4();
do tcp_watcher.connect(addr) |stream_watcher, status| {
uvdebug!("tcp_watcher.connect!");
assert!(status.is_some());
assert_eq!(status.unwrap().name(), ~"ECONNREFUSED");
stream_watcher.close(||());
}
loop_.run();
loop_.close();
}
}
#[test]
fn connect_close_ip6() {
do run_in_bare_thread() {
let mut loop_ = Loop::new();
let mut tcp_watcher = { TcpWatcher::new(&mut loop_) };
// Connect to a port where nobody is listening
let addr = next_test_ip6();
do tcp_watcher.connect(addr) |stream_watcher, status| {
uvdebug!("tcp_watcher.connect!");
assert!(status.is_some());
assert_eq!(status.unwrap().name(), ~"ECONNREFUSED");
stream_watcher.close(||());
}
loop_.run();
loop_.close();
}
}
#[test]
fn udp_bind_close_ip4() {
do run_in_bare_thread() {
let mut loop_ = Loop::new();
let mut udp_watcher = { UdpWatcher::new(&mut loop_) };
let addr = next_test_ip4();
udp_watcher.bind(addr);
udp_watcher.close(||());
loop_.run();
loop_.close();
}
}
#[test]
fn udp_bind_close_ip6() {
do run_in_bare_thread() {
let mut loop_ = Loop::new();
let mut udp_watcher = { UdpWatcher::new(&mut loop_) };
let addr = next_test_ip6();
udp_watcher.bind(addr);
udp_watcher.close(||());
loop_.run();
loop_.close();
}
}
#[test]
fn listen_ip4() {
do run_in_bare_thread() {
static MAX: int = 10;
let mut loop_ = Loop::new();
let mut server_tcp_watcher = { TcpWatcher::new(&mut loop_) };
let addr = next_test_ip4();
server_tcp_watcher.bind(addr);
let loop_ = loop_;
uvdebug!("listening");
let mut stream = server_tcp_watcher.as_stream();
let res = do stream.listen |mut server_stream_watcher, status| {
uvdebug!("listened!");
assert!(status.is_none());
let mut loop_ = loop_;
let client_tcp_watcher = TcpWatcher::new(&mut loop_);
let mut client_tcp_watcher = client_tcp_watcher.as_stream();
server_stream_watcher.accept(client_tcp_watcher);
let count_cell = Cell::new(0);
let server_stream_watcher = server_stream_watcher;
uvdebug!("starting read");
let alloc: AllocCallback = |size| {
vec_to_uv_buf(vec::from_elem(size, 0u8))
};
do client_tcp_watcher.read_start(alloc) |stream_watcher, nread, buf, status| {
uvdebug!("i'm reading!");
let buf = vec_from_uv_buf(buf);
let mut count = count_cell.take();
if status.is_none() {
uvdebug!("got {} bytes", nread);
let buf = buf.unwrap();
for byte in buf.slice(0, nread as uint).iter() {
assert!(*byte == count as u8);
uvdebug!("{}", *byte as uint);
count += 1;
}
} else {
assert_eq!(count, MAX);
do stream_watcher.close {
server_stream_watcher.close(||());
}
}
count_cell.put_back(count);
}
};
assert!(res.is_ok());
let client_thread = do Thread::start {
uvdebug!("starting client thread");
let mut loop_ = Loop::new();
let mut tcp_watcher = { TcpWatcher::new(&mut loop_) };
do tcp_watcher.connect(addr) |mut stream_watcher, status| {
uvdebug!("connecting");
assert!(status.is_none());
let msg = ~[0, 1, 2, 3, 4, 5, 6 ,7 ,8, 9];
let buf = slice_to_uv_buf(msg);
let msg_cell = Cell::new(msg);
do stream_watcher.write(buf) |stream_watcher, status| {
uvdebug!("writing");
assert!(status.is_none());
let msg_cell = Cell::new(msg_cell.take());
stream_watcher.close(||ignore(msg_cell.take()));
}
}
loop_.run();
loop_.close();
};
let mut loop_ = loop_;
loop_.run();
loop_.close();
client_thread.join();
};
}
#[test]
fn listen_ip6() {
do run_in_bare_thread() {
static MAX: int = 10;
let mut loop_ = Loop::new();
let mut server_tcp_watcher = { TcpWatcher::new(&mut loop_) };
let addr = next_test_ip6();
server_tcp_watcher.bind(addr);
let loop_ = loop_;
uvdebug!("listening");
let mut stream = server_tcp_watcher.as_stream();
let res = do stream.listen |mut server_stream_watcher, status| {
uvdebug!("listened!");
assert!(status.is_none());
let mut loop_ = loop_;
let client_tcp_watcher = TcpWatcher::new(&mut loop_);
let mut client_tcp_watcher = client_tcp_watcher.as_stream();
server_stream_watcher.accept(client_tcp_watcher);
let count_cell = Cell::new(0);
let server_stream_watcher = server_stream_watcher;
uvdebug!("starting read");
let alloc: AllocCallback = |size| {
vec_to_uv_buf(vec::from_elem(size, 0u8))
};
do client_tcp_watcher.read_start(alloc)
|stream_watcher, nread, buf, status| {
uvdebug!("i'm reading!");
let buf = vec_from_uv_buf(buf);
let mut count = count_cell.take();
if status.is_none() {
uvdebug!("got {} bytes", nread);
let buf = buf.unwrap();
let r = buf.slice(0, nread as uint);
for byte in r.iter() {
assert!(*byte == count as u8);
uvdebug!("{}", *byte as uint);
count += 1;
}
} else {
assert_eq!(count, MAX);
do stream_watcher.close {
server_stream_watcher.close(||());
}
}
count_cell.put_back(count);
}
};
assert!(res.is_ok());
let client_thread = do Thread::start {
uvdebug!("starting client thread");
let mut loop_ = Loop::new();
let mut tcp_watcher = { TcpWatcher::new(&mut loop_) };
do tcp_watcher.connect(addr) |mut stream_watcher, status| {
uvdebug!("connecting");
assert!(status.is_none());
let msg = ~[0, 1, 2, 3, 4, 5, 6 ,7 ,8, 9];
let buf = slice_to_uv_buf(msg);
let msg_cell = Cell::new(msg);
do stream_watcher.write(buf) |stream_watcher, status| {
uvdebug!("writing");
assert!(status.is_none());
let msg_cell = Cell::new(msg_cell.take());
stream_watcher.close(||ignore(msg_cell.take()));
}
}
loop_.run();
loop_.close();
};
let mut loop_ = loop_;
loop_.run();
loop_.close();
client_thread.join();
}
}
#[test]
fn udp_recv_ip4() {
do run_in_bare_thread() {
static MAX: int = 10;
let mut loop_ = Loop::new();
let server_addr = next_test_ip4();
let client_addr = next_test_ip4();
let mut server = UdpWatcher::new(&loop_);
assert!(server.bind(server_addr).is_ok());
uvdebug!("starting read");
let alloc: AllocCallback = |size| {
vec_to_uv_buf(vec::from_elem(size, 0u8))
};
do server.recv_start(alloc) |mut server, nread, buf, src, flags, status| {
server.recv_stop();
uvdebug!("i'm reading!");
assert!(status.is_none());
assert_eq!(flags, 0);
assert_eq!(src, client_addr);
let buf = vec_from_uv_buf(buf);
let mut count = 0;
uvdebug!("got {} bytes", nread);
let buf = buf.unwrap();
for &byte in buf.slice(0, nread as uint).iter() {
assert!(byte == count as u8);
uvdebug!("{}", byte as uint);
count += 1;
}
assert_eq!(count, MAX);
server.close(||{});
}
let thread = do Thread::start {
let mut loop_ = Loop::new();
let mut client = UdpWatcher::new(&loop_);
assert!(client.bind(client_addr).is_ok());
let msg = ~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let buf = slice_to_uv_buf(msg);
do client.send(buf, server_addr) |client, status| {
uvdebug!("writing");
assert!(status.is_none());
client.close(||{});
}
loop_.run();
loop_.close();
};
loop_.run();
loop_.close();
thread.join();
}
}
#[test]
fn udp_recv_ip6() {
do run_in_bare_thread() {
static MAX: int = 10;
let mut loop_ = Loop::new();
let server_addr = next_test_ip6();
let client_addr = next_test_ip6();
let mut server = UdpWatcher::new(&loop_);
assert!(server.bind(server_addr).is_ok());
uvdebug!("starting read");
let alloc: AllocCallback = |size| {
vec_to_uv_buf(vec::from_elem(size, 0u8))
};
do server.recv_start(alloc) |mut server, nread, buf, src, flags, status| {
server.recv_stop();
uvdebug!("i'm reading!");
assert!(status.is_none());
assert_eq!(flags, 0);
assert_eq!(src, client_addr);
let buf = vec_from_uv_buf(buf);
let mut count = 0;
uvdebug!("got {} bytes", nread);
let buf = buf.unwrap();
for &byte in buf.slice(0, nread as uint).iter() {
assert!(byte == count as u8);
uvdebug!("{}", byte as uint);
count += 1;
}
assert_eq!(count, MAX);
server.close(||{});
}
let thread = do Thread::start {
let mut loop_ = Loop::new();
let mut client = UdpWatcher::new(&loop_);
assert!(client.bind(client_addr).is_ok());
let msg = ~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let buf = slice_to_uv_buf(msg);
do client.send(buf, server_addr) |client, status| {
uvdebug!("writing");
assert!(status.is_none());
client.close(||{});
}
loop_.run();
loop_.close();
};
loop_.run();
loop_.close();
thread.join();
}
}
}

98
src/librustuv/pipe.rs Normal file
View File

@ -0,0 +1,98 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::libc;
use std::c_str::CString;
use super::{Loop, UvError, Watcher, NativeHandle, status_to_maybe_uv_error};
use super::ConnectionCallback;
use net;
use uvll;
pub struct Pipe(*uvll::uv_pipe_t);
impl Watcher for Pipe {}
impl Pipe {
pub fn new(loop_: &Loop, ipc: bool) -> Pipe {
unsafe {
let handle = uvll::malloc_handle(uvll::UV_NAMED_PIPE);
assert!(handle.is_not_null());
let ipc = ipc as libc::c_int;
assert_eq!(uvll::pipe_init(loop_.native_handle(), handle, ipc), 0);
let mut ret: Pipe =
NativeHandle::from_native_handle(handle);
ret.install_watcher_data();
ret
}
}
pub fn as_stream(&self) -> net::StreamWatcher {
net::StreamWatcher(**self as *uvll::uv_stream_t)
}
#[fixed_stack_segment] #[inline(never)]
pub fn open(&mut self, file: libc::c_int) -> Result<(), UvError> {
match unsafe { uvll::pipe_open(self.native_handle(), file) } {
0 => Ok(()),
n => Err(UvError(n))
}
}
#[fixed_stack_segment] #[inline(never)]
pub fn bind(&mut self, name: &CString) -> Result<(), UvError> {
do name.with_ref |name| {
match unsafe { uvll::pipe_bind(self.native_handle(), name) } {
0 => Ok(()),
n => Err(UvError(n))
}
}
}
#[fixed_stack_segment] #[inline(never)]
pub fn connect(&mut self, name: &CString, cb: ConnectionCallback) {
{
let data = self.get_watcher_data();
assert!(data.connect_cb.is_none());
data.connect_cb = Some(cb);
}
let connect = net::ConnectRequest::new();
let name = do name.with_ref |p| { p };
unsafe {
uvll::pipe_connect(connect.native_handle(),
self.native_handle(),
name,
connect_cb)
}
extern "C" fn connect_cb(req: *uvll::uv_connect_t, status: libc::c_int) {
let connect_request: net::ConnectRequest =
NativeHandle::from_native_handle(req);
let mut stream_watcher = connect_request.stream();
connect_request.delete();
let cb = stream_watcher.get_watcher_data().connect_cb.take_unwrap();
let status = status_to_maybe_uv_error(status);
cb(stream_watcher, status);
}
}
}
impl NativeHandle<*uvll::uv_pipe_t> for Pipe {
fn from_native_handle(handle: *uvll::uv_pipe_t) -> Pipe {
Pipe(handle)
}
fn native_handle(&self) -> *uvll::uv_pipe_t {
match self { &Pipe(ptr) => ptr }
}
}

202
src/librustuv/process.rs Normal file
View File

@ -0,0 +1,202 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::cell::Cell;
use std::libc;
use std::ptr;
use std::vec;
use std::rt::io::process::*;
use super::{Watcher, Loop, NativeHandle, UvError};
use super::{status_to_maybe_uv_error, ExitCallback};
use uvio::{UvPipeStream, UvUnboundPipe};
use uvll;
/// A process wraps the handle of the underlying uv_process_t.
pub struct Process(*uvll::uv_process_t);
impl Watcher for Process {}
impl Process {
/// Creates a new process, ready to spawn inside an event loop
pub fn new() -> Process {
let handle = unsafe { uvll::malloc_handle(uvll::UV_PROCESS) };
assert!(handle.is_not_null());
let mut ret: Process = NativeHandle::from_native_handle(handle);
ret.install_watcher_data();
return ret;
}
/// Spawn a new process inside the specified event loop.
///
/// The `config` variable will be passed down to libuv, and the `exit_cb`
/// will be run only once, when the process exits.
///
/// Returns either the corresponding process object or an error which
/// occurred.
pub fn spawn(&mut self, loop_: &Loop, config: ProcessConfig,
exit_cb: ExitCallback)
-> Result<~[Option<~UvPipeStream>], UvError>
{
let cwd = config.cwd.map(|s| s.to_c_str());
extern fn on_exit(p: *uvll::uv_process_t,
exit_status: libc::c_int,
term_signal: libc::c_int) {
let mut p: Process = NativeHandle::from_native_handle(p);
let err = match exit_status {
0 => None,
_ => status_to_maybe_uv_error(-1)
};
p.get_watcher_data().exit_cb.take_unwrap()(p,
exit_status as int,
term_signal as int,
err);
}
let io = config.io;
let mut stdio = vec::with_capacity::<uvll::uv_stdio_container_t>(io.len());
let mut ret_io = vec::with_capacity(io.len());
unsafe {
vec::raw::set_len(&mut stdio, io.len());
for (slot, other) in stdio.iter().zip(io.iter()) {
let io = set_stdio(slot as *uvll::uv_stdio_container_t, other,
loop_);
ret_io.push(io);
}
}
let exit_cb = Cell::new(exit_cb);
let ret_io = Cell::new(ret_io);
do with_argv(config.program, config.args) |argv| {
do with_env(config.env) |envp| {
let options = uvll::uv_process_options_t {
exit_cb: on_exit,
file: unsafe { *argv },
args: argv,
env: envp,
cwd: match cwd {
Some(ref cwd) => cwd.with_ref(|p| p),
None => ptr::null(),
},
flags: 0,
stdio_count: stdio.len() as libc::c_int,
stdio: stdio.as_imm_buf(|p, _| p),
uid: 0,
gid: 0,
};
match unsafe {
uvll::spawn(loop_.native_handle(), **self, options)
} {
0 => {
(*self).get_watcher_data().exit_cb = Some(exit_cb.take());
Ok(ret_io.take())
}
err => Err(UvError(err))
}
}
}
}
/// Sends a signal to this process.
///
/// This is a wrapper around `uv_process_kill`
pub fn kill(&self, signum: int) -> Result<(), UvError> {
match unsafe {
uvll::process_kill(self.native_handle(), signum as libc::c_int)
} {
0 => Ok(()),
err => Err(UvError(err))
}
}
/// Returns the process id of a spawned process
pub fn pid(&self) -> libc::pid_t {
unsafe { uvll::process_pid(**self) as libc::pid_t }
}
}
unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t,
io: &StdioContainer,
loop_: &Loop) -> Option<~UvPipeStream> {
match *io {
Ignored => {
uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE);
None
}
InheritFd(fd) => {
uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_FD);
uvll::set_stdio_container_fd(dst, fd);
None
}
CreatePipe(readable, writable) => {
let mut flags = uvll::STDIO_CREATE_PIPE as libc::c_int;
if readable {
flags |= uvll::STDIO_READABLE_PIPE as libc::c_int;
}
if writable {
flags |= uvll::STDIO_WRITABLE_PIPE as libc::c_int;
}
let pipe = UvUnboundPipe::new(loop_);
let handle = pipe.pipe.as_stream().native_handle();
uvll::set_stdio_container_flags(dst, flags);
uvll::set_stdio_container_stream(dst, handle);
Some(~UvPipeStream::new(pipe))
}
}
}
/// Converts the program and arguments to the argv array expected by libuv
fn with_argv<T>(prog: &str, args: &[~str], f: &fn(**libc::c_char) -> T) -> T {
// First, allocation space to put all the C-strings (we need to have
// ownership of them somewhere
let mut c_strs = vec::with_capacity(args.len() + 1);
c_strs.push(prog.to_c_str());
for arg in args.iter() {
c_strs.push(arg.to_c_str());
}
// Next, create the char** array
let mut c_args = vec::with_capacity(c_strs.len() + 1);
for s in c_strs.iter() {
c_args.push(s.with_ref(|p| p));
}
c_args.push(ptr::null());
c_args.as_imm_buf(|buf, _| f(buf))
}
/// Converts the environment to the env array expected by libuv
fn with_env<T>(env: Option<&[(~str, ~str)]>, f: &fn(**libc::c_char) -> T) -> T {
let env = match env {
Some(s) => s,
None => { return f(ptr::null()); }
};
// As with argv, create some temporary storage and then the actual array
let mut envp = vec::with_capacity(env.len());
for &(ref key, ref value) in env.iter() {
envp.push(format!("{}={}", *key, *value).to_c_str());
}
let mut c_envp = vec::with_capacity(envp.len() + 1);
for s in envp.iter() {
c_envp.push(s.with_ref(|p| p));
}
c_envp.push(ptr::null());
c_envp.as_imm_buf(|buf, _| f(buf))
}
impl NativeHandle<*uvll::uv_process_t> for Process {
fn from_native_handle(handle: *uvll::uv_process_t) -> Process {
Process(handle)
}
fn native_handle(&self) -> *uvll::uv_process_t {
match self { &Process(ptr) => ptr }
}
}

424
src/librustuv/rustuv.rs Normal file
View File

@ -0,0 +1,424 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*!
Bindings to libuv, along with the default implementation of `std::rt::rtio`.
UV types consist of the event loop (Loop), Watchers, Requests and
Callbacks.
Watchers and Requests encapsulate pointers to uv *handles*, which have
subtyping relationships with each other. This subtyping is reflected
in the bindings with explicit or implicit coercions. For example, an
upcast from TcpWatcher to StreamWatcher is done with
`tcp_watcher.as_stream()`. In other cases a callback on a specific
type of watcher will be passed a watcher of a supertype.
Currently all use of Request types (connect/write requests) are
encapsulated in the bindings and don't need to be dealt with by the
caller.
# Safety note
Due to the complex lifecycle of uv handles, as well as compiler bugs,
this module is not memory safe and requires explicit memory management,
via `close` and `delete` methods.
*/
#[link(name = "rustuv",
vers = "0.9-pre",
uuid = "f3719011-0459-9b86-b11c-29265c0d0864",
url = "https://github.com/mozilla/rust/tree/master/src/librustuv")];
#[license = "MIT/ASL2"];
#[crate_type = "lib"];
#[feature(macro_rules, globs)];
use std::str::raw::from_c_str;
use std::vec;
use std::ptr;
use std::str;
use std::libc::{c_void, c_int, size_t, malloc, free};
use std::cast::transmute;
use std::ptr::null;
use std::unstable::finally::Finally;
use std::rt::io::net::ip::SocketAddr;
use std::rt::io::signal::Signum;
use std::rt::io::IoError;
//#[cfg(test)] use unstable::run_in_bare_thread;
pub use self::file::{FsRequest};
pub use self::net::{StreamWatcher, TcpWatcher, UdpWatcher};
pub use self::idle::IdleWatcher;
pub use self::timer::TimerWatcher;
pub use self::async::AsyncWatcher;
pub use self::process::Process;
pub use self::pipe::Pipe;
pub use self::signal::SignalWatcher;
mod macros;
/// The implementation of `rtio` for libuv
pub mod uvio;
/// C bindings to libuv
pub mod uvll;
pub mod file;
pub mod net;
pub mod idle;
pub mod timer;
pub mod async;
pub mod addrinfo;
pub mod process;
pub mod pipe;
pub mod tty;
pub mod signal;
/// XXX: Loop(*handle) is buggy with destructors. Normal structs
/// with dtors may not be destructured, but tuple structs can,
/// but the results are not correct.
pub struct Loop {
priv handle: *uvll::uv_loop_t
}
pub struct Handle(*uvll::uv_handle_t);
impl Watcher for Handle {}
impl NativeHandle<*uvll::uv_handle_t> for Handle {
fn from_native_handle(h: *uvll::uv_handle_t) -> Handle { Handle(h) }
fn native_handle(&self) -> *uvll::uv_handle_t { **self }
}
/// The trait implemented by uv 'watchers' (handles). Watchers are
/// non-owning wrappers around the uv handles and are not completely
/// safe - there may be multiple instances for a single underlying
/// handle. Watchers are generally created, then `start`ed, `stop`ed
/// and `close`ed, but due to their complex life cycle may not be
/// entirely memory safe if used in unanticipated patterns.
pub trait Watcher { }
pub trait Request { }
/// A type that wraps a native handle
pub trait NativeHandle<T> {
fn from_native_handle(T) -> Self;
fn native_handle(&self) -> T;
}
impl Loop {
pub fn new() -> Loop {
let handle = unsafe { uvll::loop_new() };
assert!(handle.is_not_null());
NativeHandle::from_native_handle(handle)
}
pub fn run(&mut self) {
unsafe { uvll::run(self.native_handle()) };
}
pub fn close(&mut self) {
unsafe { uvll::loop_delete(self.native_handle()) };
}
}
impl NativeHandle<*uvll::uv_loop_t> for Loop {
fn from_native_handle(handle: *uvll::uv_loop_t) -> Loop {
Loop { handle: handle }
}
fn native_handle(&self) -> *uvll::uv_loop_t {
self.handle
}
}
// XXX: The uv alloc callback also has a *uv_handle_t arg
pub type AllocCallback = ~fn(uint) -> Buf;
pub type ReadCallback = ~fn(StreamWatcher, int, Buf, Option<UvError>);
pub type NullCallback = ~fn();
pub type IdleCallback = ~fn(IdleWatcher, Option<UvError>);
pub type ConnectionCallback = ~fn(StreamWatcher, Option<UvError>);
pub type FsCallback = ~fn(&mut FsRequest, Option<UvError>);
// first int is exit_status, second is term_signal
pub type ExitCallback = ~fn(Process, int, int, Option<UvError>);
pub type TimerCallback = ~fn(TimerWatcher, Option<UvError>);
pub type AsyncCallback = ~fn(AsyncWatcher, Option<UvError>);
pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option<UvError>);
pub type UdpSendCallback = ~fn(UdpWatcher, Option<UvError>);
pub type SignalCallback = ~fn(SignalWatcher, Signum);
/// Callbacks used by StreamWatchers, set as custom data on the foreign handle.
/// XXX: Would be better not to have all watchers allocate room for all callback types.
struct WatcherData {
read_cb: Option<ReadCallback>,
write_cb: Option<ConnectionCallback>,
connect_cb: Option<ConnectionCallback>,
close_cb: Option<NullCallback>,
alloc_cb: Option<AllocCallback>,
idle_cb: Option<IdleCallback>,
timer_cb: Option<TimerCallback>,
async_cb: Option<AsyncCallback>,
udp_recv_cb: Option<UdpReceiveCallback>,
udp_send_cb: Option<UdpSendCallback>,
exit_cb: Option<ExitCallback>,
signal_cb: Option<SignalCallback>,
}
pub trait WatcherInterop {
fn event_loop(&self) -> Loop;
fn install_watcher_data(&mut self);
fn get_watcher_data<'r>(&'r mut self) -> &'r mut WatcherData;
fn drop_watcher_data(&mut self);
fn close(self, cb: NullCallback);
fn close_async(self);
}
impl<H, W: Watcher + NativeHandle<*H>> WatcherInterop for W {
/// Get the uv event loop from a Watcher
fn event_loop(&self) -> Loop {
unsafe {
let handle = self.native_handle();
let loop_ = uvll::get_loop_for_uv_handle(handle);
NativeHandle::from_native_handle(loop_)
}
}
fn install_watcher_data(&mut self) {
unsafe {
let data = ~WatcherData {
read_cb: None,
write_cb: None,
connect_cb: None,
close_cb: None,
alloc_cb: None,
idle_cb: None,
timer_cb: None,
async_cb: None,
udp_recv_cb: None,
udp_send_cb: None,
exit_cb: None,
signal_cb: None,
};
let data = transmute::<~WatcherData, *c_void>(data);
uvll::set_data_for_uv_handle(self.native_handle(), data);
}
}
fn get_watcher_data<'r>(&'r mut self) -> &'r mut WatcherData {
unsafe {
let data = uvll::get_data_for_uv_handle(self.native_handle());
let data = transmute::<&*c_void, &mut ~WatcherData>(&data);
return &mut **data;
}
}
fn drop_watcher_data(&mut self) {
unsafe {
let data = uvll::get_data_for_uv_handle(self.native_handle());
let _data = transmute::<*c_void, ~WatcherData>(data);
uvll::set_data_for_uv_handle(self.native_handle(), null::<()>());
}
}
fn close(self, cb: NullCallback) {
let mut this = self;
{
let data = this.get_watcher_data();
assert!(data.close_cb.is_none());
data.close_cb = Some(cb);
}
unsafe { uvll::close(this.native_handle(), close_cb); }
extern fn close_cb(handle: *uvll::uv_handle_t) {
let mut h: Handle = NativeHandle::from_native_handle(handle);
h.get_watcher_data().close_cb.take_unwrap()();
h.drop_watcher_data();
unsafe { uvll::free_handle(handle as *c_void) }
}
}
fn close_async(self) {
unsafe { uvll::close(self.native_handle(), close_cb); }
extern fn close_cb(handle: *uvll::uv_handle_t) {
let mut h: Handle = NativeHandle::from_native_handle(handle);
h.drop_watcher_data();
unsafe { uvll::free_handle(handle as *c_void) }
}
}
}
// XXX: Need to define the error constants like EOF so they can be
// compared to the UvError type
pub struct UvError(c_int);
impl UvError {
pub fn name(&self) -> ~str {
unsafe {
let inner = match self { &UvError(a) => a };
let name_str = uvll::err_name(inner);
assert!(name_str.is_not_null());
from_c_str(name_str)
}
}
pub fn desc(&self) -> ~str {
unsafe {
let inner = match self { &UvError(a) => a };
let desc_str = uvll::strerror(inner);
assert!(desc_str.is_not_null());
from_c_str(desc_str)
}
}
pub fn is_eof(&self) -> bool {
**self == uvll::EOF
}
}
impl ToStr for UvError {
fn to_str(&self) -> ~str {
format!("{}: {}", self.name(), self.desc())
}
}
#[test]
fn error_smoke_test() {
let err: UvError = UvError(uvll::EOF);
assert_eq!(err.to_str(), ~"EOF: end of file");
}
pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
unsafe {
// Importing error constants
use uvll::*;
use std::rt::io::*;
// uv error descriptions are static
let c_desc = uvll::strerror(*uverr);
let desc = str::raw::c_str_to_static_slice(c_desc);
let kind = match *uverr {
UNKNOWN => OtherIoError,
OK => OtherIoError,
EOF => EndOfFile,
EACCES => PermissionDenied,
ECONNREFUSED => ConnectionRefused,
ECONNRESET => ConnectionReset,
ENOTCONN => NotConnected,
EPIPE => BrokenPipe,
ECONNABORTED => ConnectionAborted,
err => {
uvdebug!("uverr.code {}", err as int);
// XXX: Need to map remaining uv error types
OtherIoError
}
};
IoError {
kind: kind,
desc: desc,
detail: None
}
}
}
/// Given a uv handle, convert a callback status to a UvError
pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError>
{
if status >= 0 {
None
} else {
Some(UvError(status))
}
}
/// The uv buffer type
pub type Buf = uvll::uv_buf_t;
pub fn empty_buf() -> Buf {
uvll::uv_buf_t {
base: null(),
len: 0,
}
}
/// Borrow a slice to a Buf
pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
let data = vec::raw::to_ptr(v);
unsafe { uvll::buf_init(data, v.len()) }
}
// XXX: Do these conversions without copying
/// Transmute an owned vector to a Buf
pub fn vec_to_uv_buf(v: ~[u8]) -> Buf {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let data = malloc(v.len() as size_t) as *u8;
assert!(data.is_not_null());
do v.as_imm_buf |b, l| {
let data = data as *mut u8;
ptr::copy_memory(data, b, l)
}
uvll::buf_init(data, v.len())
}
}
/// Transmute a Buf that was once a ~[u8] back to ~[u8]
pub fn vec_from_uv_buf(buf: Buf) -> Option<~[u8]> {
#[fixed_stack_segment]; #[inline(never)];
if !(buf.len == 0 && buf.base.is_null()) {
let v = unsafe { vec::from_buf(buf.base, buf.len as uint) };
unsafe { free(buf.base as *c_void) };
return Some(v);
} else {
// No buffer
uvdebug!("No buffer!");
return None;
}
}
/*
#[test]
fn test_slice_to_uv_buf() {
let slice = [0, .. 20];
let buf = slice_to_uv_buf(slice);
assert!(buf.len == 20);
unsafe {
let base = transmute::<*u8, *mut u8>(buf.base);
(*base) = 1;
(*ptr::mut_offset(base, 1)) = 2;
}
assert!(slice[0] == 1);
assert!(slice[1] == 2);
}
#[test]
fn loop_smoke_test() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
loop_.run();
loop_.close();
}
}
*/

72
src/librustuv/signal.rs Normal file
View File

@ -0,0 +1,72 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::cast;
use std::libc::c_int;
use std::rt::io::signal::Signum;
use super::{Loop, NativeHandle, SignalCallback, UvError, Watcher};
use uvll;
pub struct SignalWatcher(*uvll::uv_signal_t);
impl Watcher for SignalWatcher { }
impl SignalWatcher {
pub fn new(loop_: &mut Loop) -> SignalWatcher {
unsafe {
let handle = uvll::malloc_handle(uvll::UV_SIGNAL);
assert!(handle.is_not_null());
assert!(0 == uvll::signal_init(loop_.native_handle(), handle));
let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle);
watcher.install_watcher_data();
return watcher;
}
}
pub fn start(&mut self, signum: Signum, callback: SignalCallback)
-> Result<(), UvError>
{
return unsafe {
match uvll::signal_start(self.native_handle(), signal_cb,
signum as c_int) {
0 => {
let data = self.get_watcher_data();
data.signal_cb = Some(callback);
Ok(())
}
n => Err(UvError(n)),
}
};
extern fn signal_cb(handle: *uvll::uv_signal_t, signum: c_int) {
let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle);
let data = watcher.get_watcher_data();
let cb = data.signal_cb.get_ref();
(*cb)(watcher, unsafe { cast::transmute(signum as int) });
}
}
pub fn stop(&mut self) {
unsafe {
uvll::signal_stop(self.native_handle());
}
}
}
impl NativeHandle<*uvll::uv_signal_t> for SignalWatcher {
fn from_native_handle(handle: *uvll::uv_signal_t) -> SignalWatcher {
SignalWatcher(handle)
}
fn native_handle(&self) -> *uvll::uv_signal_t {
match self { &SignalWatcher(ptr) => ptr }
}
}

157
src/librustuv/timer.rs Normal file
View File

@ -0,0 +1,157 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::libc::c_int;
use uvll;
use super::{Watcher, Loop, NativeHandle, TimerCallback, status_to_maybe_uv_error};
pub struct TimerWatcher(*uvll::uv_timer_t);
impl Watcher for TimerWatcher { }
impl TimerWatcher {
pub fn new(loop_: &mut Loop) -> TimerWatcher {
unsafe {
let handle = uvll::malloc_handle(uvll::UV_TIMER);
assert!(handle.is_not_null());
assert!(0 == uvll::timer_init(loop_.native_handle(), handle));
let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
watcher.install_watcher_data();
return watcher;
}
}
pub fn start(&mut self, timeout: u64, repeat: u64, cb: TimerCallback) {
{
let data = self.get_watcher_data();
data.timer_cb = Some(cb);
}
unsafe {
uvll::timer_start(self.native_handle(), timer_cb, timeout, repeat);
}
extern fn timer_cb(handle: *uvll::uv_timer_t, status: c_int) {
let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
let data = watcher.get_watcher_data();
let cb = data.timer_cb.get_ref();
let status = status_to_maybe_uv_error(status);
(*cb)(watcher, status);
}
}
pub fn stop(&mut self) {
unsafe {
uvll::timer_stop(self.native_handle());
}
}
}
impl NativeHandle<*uvll::uv_timer_t> for TimerWatcher {
fn from_native_handle(handle: *uvll::uv_timer_t) -> TimerWatcher {
TimerWatcher(handle)
}
fn native_handle(&self) -> *uvll::uv_idle_t {
match self { &TimerWatcher(ptr) => ptr }
}
}
#[cfg(test)]
mod test {
use super::*;
use Loop;
use std::unstable::run_in_bare_thread;
#[test]
fn smoke_test() {
do run_in_bare_thread {
let mut count = 0;
let count_ptr: *mut int = &mut count;
let mut loop_ = Loop::new();
let mut timer = TimerWatcher::new(&mut loop_);
do timer.start(10, 0) |timer, status| {
assert!(status.is_none());
unsafe { *count_ptr += 1 };
timer.close(||());
}
loop_.run();
loop_.close();
assert!(count == 1);
}
}
#[test]
fn start_twice() {
do run_in_bare_thread {
let mut count = 0;
let count_ptr: *mut int = &mut count;
let mut loop_ = Loop::new();
let mut timer = TimerWatcher::new(&mut loop_);
do timer.start(10, 0) |timer, status| {
let mut timer = timer;
assert!(status.is_none());
unsafe { *count_ptr += 1 };
do timer.start(10, 0) |timer, status| {
assert!(status.is_none());
unsafe { *count_ptr += 1 };
timer.close(||());
}
}
loop_.run();
loop_.close();
assert!(count == 2);
}
}
#[test]
fn repeat_stop() {
do run_in_bare_thread {
let mut count = 0;
let count_ptr: *mut int = &mut count;
let mut loop_ = Loop::new();
let mut timer = TimerWatcher::new(&mut loop_);
do timer.start(1, 2) |timer, status| {
assert!(status.is_none());
unsafe {
*count_ptr += 1;
if *count_ptr == 10 {
// Stop the timer and do something else
let mut timer = timer;
timer.stop();
// Freeze timer so it can be captured
let timer = timer;
let mut loop_ = timer.event_loop();
let mut timer2 = TimerWatcher::new(&mut loop_);
do timer2.start(10, 0) |timer2, _| {
*count_ptr += 1;
timer2.close(||());
// Restart the original timer
let mut timer = timer;
do timer.start(1, 0) |timer, _| {
*count_ptr += 1;
timer.close(||());
}
}
}
};
}
loop_.run();
loop_.close();
assert!(count == 12);
}
}
}

83
src/librustuv/tty.rs Normal file
View File

@ -0,0 +1,83 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::libc;
use super::{Watcher, Loop, NativeHandle, UvError};
use net;
use uvll;
/// A process wraps the handle of the underlying uv_process_t.
pub struct TTY(*uvll::uv_tty_t);
impl Watcher for TTY {}
impl TTY {
#[fixed_stack_segment] #[inline(never)]
pub fn new(loop_: &Loop, fd: libc::c_int, readable: bool) ->
Result<TTY, UvError>
{
let handle = unsafe { uvll::malloc_handle(uvll::UV_TTY) };
assert!(handle.is_not_null());
let ret = unsafe {
uvll::tty_init(loop_.native_handle(), handle, fd as libc::c_int,
readable as libc::c_int)
};
match ret {
0 => {
let mut ret: TTY = NativeHandle::from_native_handle(handle);
ret.install_watcher_data();
Ok(ret)
}
n => {
unsafe { uvll::free_handle(handle); }
Err(UvError(n))
}
}
}
pub fn as_stream(&self) -> net::StreamWatcher {
net::StreamWatcher(**self as *uvll::uv_stream_t)
}
#[fixed_stack_segment] #[inline(never)]
pub fn set_mode(&self, raw: bool) -> Result<(), UvError> {
let raw = raw as libc::c_int;
match unsafe { uvll::tty_set_mode(self.native_handle(), raw) } {
0 => Ok(()),
n => Err(UvError(n))
}
}
#[fixed_stack_segment] #[inline(never)] #[allow(unused_mut)]
pub fn get_winsize(&self) -> Result<(int, int), UvError> {
let mut width: libc::c_int = 0;
let mut height: libc::c_int = 0;
let widthptr: *libc::c_int = &width;
let heightptr: *libc::c_int = &width;
match unsafe { uvll::tty_get_winsize(self.native_handle(),
widthptr, heightptr) } {
0 => Ok((width as int, height as int)),
n => Err(UvError(n))
}
}
}
impl NativeHandle<*uvll::uv_tty_t> for TTY {
fn from_native_handle(handle: *uvll::uv_tty_t) -> TTY {
TTY(handle)
}
fn native_handle(&self) -> *uvll::uv_tty_t {
match self { &TTY(ptr) => ptr }
}
}

2526
src/librustuv/uvio.rs Normal file

File diff suppressed because it is too large Load Diff

1174
src/librustuv/uvll.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,8 @@ use container::MutableSet;
use hashmap::HashSet;
use option::{Some, None, Option};
use vec::ImmutableVector;
#[cfg(not(stage0))]
use rt::rtio::EventLoop;
// Need to tell the linker on OS X to not barf on undefined symbols
// and instead look them up at runtime, which we need to resolve
@ -25,18 +27,32 @@ pub struct ModEntry<'self> {
log_level: *mut u32
}
#[cfg(stage0)]
pub struct CrateMap<'self> {
priv version: i32,
priv entries: &'self [ModEntry<'self>],
priv children: &'self [&'self CrateMap<'self>]
version: i32,
entries: &'self [ModEntry<'self>],
children: &'self [&'self CrateMap<'self>]
}
#[cfg(not(stage0))]
pub struct CrateMap<'self> {
version: i32,
entries: &'self [ModEntry<'self>],
children: &'self [&'self CrateMap<'self>],
event_loop_factory: Option<extern "C" fn() -> ~EventLoop>,
}
#[cfg(not(windows))]
pub fn get_crate_map() -> Option<&'static CrateMap<'static>> {
extern {
#[cfg(stage0)]
#[weak_linkage]
#[link_name = "_rust_crate_map_toplevel"]
static CRATE_MAP: CrateMap<'static>;
#[cfg(not(stage0))]
#[crate_map]
static CRATE_MAP: CrateMap<'static>;
}
let ptr: (*CrateMap) = &'static CRATE_MAP;
@ -108,6 +124,7 @@ pub fn iter_crate_map<'a>(crate_map: &'a CrateMap<'a>, f: &fn(&ModEntry)) {
#[cfg(test)]
mod tests {
use option::None;
use rt::crate_map::{CrateMap, ModEntry, iter_crate_map};
#[test]
@ -121,13 +138,15 @@ mod tests {
let child_crate = CrateMap {
version: 2,
entries: entries,
children: []
children: [],
event_loop_factory: None,
};
let root_crate = CrateMap {
version: 2,
entries: [],
children: [&child_crate, &child_crate]
children: [&child_crate, &child_crate],
event_loop_factory: None,
};
let mut cnt = 0;
@ -150,7 +169,8 @@ mod tests {
ModEntry { name: "c::m1", log_level: &mut level2},
ModEntry { name: "c::m2", log_level: &mut level3},
],
children: []
children: [],
event_loop_factory: None,
};
let child_crate1 = CrateMap {
@ -158,7 +178,8 @@ mod tests {
entries: [
ModEntry { name: "t::f1", log_level: &mut 1},
],
children: [&child_crate2]
children: [&child_crate2],
event_loop_factory: None,
};
let root_crate = CrateMap {
@ -166,7 +187,8 @@ mod tests {
entries: [
ModEntry { name: "t::f2", log_level: &mut 0},
],
children: [&child_crate1]
children: [&child_crate1],
event_loop_factory: None,
};
let mut cnt = 0;

View File

@ -383,7 +383,8 @@ mod test {
// on windows
assert!(e.kind == ConnectionReset ||
e.kind == BrokenPipe ||
e.kind == ConnectionAborted);
e.kind == ConnectionAborted,
"unknown error: {:?}", e);
stop = true;
}).inside {
stream.write(buf);
@ -420,7 +421,8 @@ mod test {
// on windows
assert!(e.kind == ConnectionReset ||
e.kind == BrokenPipe ||
e.kind == ConnectionAborted);
e.kind == ConnectionAborted,
"unknown error: {:?}", e);
stop = true;
}).inside {
stream.write(buf);

View File

@ -68,7 +68,6 @@ use rt::sched::{Scheduler, Shutdown};
use rt::sleeper_list::SleeperList;
use rt::task::UnwindResult;
use rt::task::{Task, SchedTask, GreenTask, Sched};
use rt::uv::uvio::UvEventLoop;
use unstable::atomics::{AtomicInt, AtomicBool, SeqCst};
use unstable::sync::UnsafeArc;
use vec::{OwnedVector, MutableVector, ImmutableVector};
@ -87,15 +86,13 @@ pub use self::util::set_exit_status;
// method...
pub use self::util::default_sched_threads;
// Re-export of the functionality in the kill module
pub use self::kill::{KillHandle, BlockedTask};
// XXX: these probably shouldn't be public...
#[doc(hidden)]
pub mod shouldnt_be_public {
pub use super::sched::Scheduler;
pub use super::kill::KillHandle;
pub use super::thread::Thread;
pub use super::work_queue::WorkQueue;
pub use super::select::SelectInner;
pub use super::rtio::EventLoop;
pub use super::select::{SelectInner, SelectPortInner};
pub use super::local_ptr::maybe_tls_key;
}
@ -116,15 +113,16 @@ pub mod task;
mod kill;
/// The coroutine task scheduler, built on the `io` event loop.
mod sched;
pub mod sched;
/// Synchronous I/O.
pub mod io;
/// The EventLoop and internal synchronous I/O interface.
mod rtio;
pub mod rtio;
/// libuv and default rtio implementation.
#[cfg(stage0)]
pub mod uv;
/// The Local trait for types that are accessible via thread-local
@ -132,10 +130,10 @@ pub mod uv;
pub mod local;
/// A parallel work-stealing deque.
mod work_queue;
pub mod work_queue;
/// A parallel queue.
mod message_queue;
pub mod message_queue;
/// A mostly lock-free multi-producer, single consumer queue.
mod mpsc_queue;
@ -144,7 +142,7 @@ mod mpsc_queue;
mod mpmc_bounded_queue;
/// A parallel data structure for tracking sleeping schedulers.
mod sleeper_list;
pub mod sleeper_list;
/// Stack segments and caching.
pub mod stack;
@ -153,7 +151,7 @@ pub mod stack;
mod context;
/// Bindings to system threading libraries.
mod thread;
pub mod thread;
/// The runtime configuration, read from environment variables.
pub mod env;
@ -289,7 +287,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
rtdebug!("inserting a regular scheduler");
// Every scheduler is driven by an I/O event loop.
let loop_ = ~UvEventLoop::new() as ~rtio::EventLoop;
let loop_ = new_event_loop();
let mut sched = ~Scheduler::new(loop_,
work_queue.clone(),
work_queues.clone(),
@ -313,7 +311,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
// set.
let work_queue = WorkQueue::new();
let main_loop = ~UvEventLoop::new() as ~rtio::EventLoop;
let main_loop = new_event_loop();
let mut main_sched = ~Scheduler::new_special(main_loop,
work_queue,
work_queues.clone(),
@ -327,7 +325,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
// waking up schedulers for work stealing; since this is a
// non-work-stealing scheduler it should not be adding itself
// to the list.
main_handle.send_shutdown();
main_handle.send(Shutdown);
Some(main_sched)
} else {
None
@ -464,3 +462,29 @@ pub fn in_green_task_context() -> bool {
}
}
}
#[cfg(stage0)]
pub fn new_event_loop() -> ~rtio::EventLoop {
use rt::uv::uvio::UvEventLoop;
~UvEventLoop::new() as ~rtio::EventLoop
}
#[cfg(not(stage0))]
pub fn new_event_loop() -> ~rtio::EventLoop {
#[fixed_stack_segment]; #[allow(cstack)];
match crate_map::get_crate_map() {
None => {}
Some(map) => {
match map.event_loop_factory {
None => {}
Some(factory) => return factory()
}
}
}
// If the crate map didn't specify a factory to create an event loop, then
// instead just use a basic event loop missing all I/O services to at least
// get the scheduler running.
return basic::event_loop();
}

View File

@ -529,7 +529,7 @@ impl Scheduler {
match self.sleeper_list.casual_pop() {
Some(handle) => {
let mut handle = handle;
let mut handle = handle;
handle.send(Wake)
}
None => { (/* pass */) }
@ -800,12 +800,6 @@ impl SchedHandle {
self.queue.push(msg);
self.remote.fire();
}
pub fn send_task_from_friend(&mut self, friend: ~Task) {
self.send(TaskFromFriend(friend));
}
pub fn send_shutdown(&mut self) {
self.send(Shutdown);
}
}
struct CleanupJob {
@ -1001,7 +995,6 @@ mod test {
#[test]
fn test_schedule_home_states() {
use rt::sleeper_list::SleeperList;
use rt::work_queue::WorkQueue;
use rt::sched::Shutdown;
@ -1248,15 +1241,15 @@ mod test {
use comm::{GenericPort, GenericChan};
do run_in_mt_newsched_task {
let (end_port, end_chan) = oneshot();
let (end_port, end_chan) = oneshot();
let n_tasks = 10;
let token = 2000;
let (p, ch1) = stream();
let (p, ch1) = stream();
let mut p = p;
ch1.send((token, end_chan));
let mut i = 2;
ch1.send((token, end_chan));
let mut i = 2;
while i <= n_tasks {
let (next_p, ch) = stream();
let imm_i = i;

View File

@ -24,13 +24,12 @@ use rand;
use result::{Result, Ok, Err};
use rt::basic;
use rt::comm::oneshot;
use rt::rtio::EventLoop;
use rt::new_event_loop;
use rt::sched::Scheduler;
use rt::sleeper_list::SleeperList;
use rt::task::Task;
use rt::task::UnwindResult;
use rt::thread::Thread;
use rt::uv::uvio::UvEventLoop;
use rt::work_queue::WorkQueue;
use unstable::{run_in_bare_thread};
use vec::{OwnedVector, MutableVector, ImmutableVector};
@ -40,7 +39,7 @@ pub fn new_test_uv_sched() -> Scheduler {
let queue = WorkQueue::new();
let queues = ~[queue.clone()];
let mut sched = Scheduler::new(~UvEventLoop::new() as ~EventLoop,
let mut sched = Scheduler::new(new_event_loop(),
queue,
queues,
SleeperList::new());
@ -237,7 +236,7 @@ pub fn run_in_mt_newsched_task(f: ~fn()) {
}
for i in range(0u, nthreads) {
let loop_ = ~UvEventLoop::new() as ~EventLoop;
let loop_ = new_event_loop();
let mut sched = ~Scheduler::new(loop_,
work_queues[i].clone(),
work_queues.clone(),

View File

@ -236,6 +236,12 @@ impl EventLoop for UvEventLoop {
}
}
#[cfg(not(stage0))]
#[lang = "event_loop_factory"]
pub extern "C" fn new_loop() -> ~EventLoop {
~UvEventLoop::new() as ~EventLoop
}
pub struct UvPausibleIdleCallback {
priv watcher: IdleWatcher,
priv idle_flag: bool,

View File

@ -18,7 +18,9 @@ use option::*;
// use either::{Either, Left, Right};
// use rt::kill::BlockedTask;
use rt::local::Local;
use rt::shouldnt_be_public::{EventLoop, Scheduler, SelectInner, SelectPortInner};
use rt::rtio::EventLoop;
use rt::sched::Scheduler;
use rt::shouldnt_be_public::{SelectInner, SelectPortInner};
use task;
use unstable::finally::Finally;
use vec::{OwnedVector, MutableVector};

View File

@ -69,8 +69,13 @@ they contained the following prologue:
#[deny(non_camel_case_types)];
#[deny(missing_doc)];
// When testing libstd, bring in libuv as the I/O backend so tests can print
// things and all of the std::rt::io tests have an I/O interface to run on top
// of
#[cfg(test)] extern mod rustuv(vers = "0.9-pre");
// Make extra accessible for benchmarking
#[cfg(test)] extern mod extra(vers="0.9-pre");
#[cfg(test)] extern mod extra(vers = "0.9-pre");
// Make std testable by not duplicating lang items. See #2912
#[cfg(test)] extern mod realstd(name = "std");

View File

@ -578,7 +578,7 @@ pub fn deschedule() {
//! Yield control to the task scheduler
use rt::local::Local;
use rt::shouldnt_be_public::Scheduler;
use rt::sched::Scheduler;
// FIXME(#7544): Optimize this, since we know we won't block.
let sched: ~Scheduler = Local::take();
@ -1094,7 +1094,7 @@ fn test_try_fail() {
#[cfg(test)]
fn get_sched_id() -> int {
do Local::borrow |sched: &mut ::rt::shouldnt_be_public::Scheduler| {
do Local::borrow |sched: &mut ::rt::sched::Scheduler| {
sched.sched_id() as int
}
}

View File

@ -80,13 +80,14 @@ use comm::{Chan, GenericChan, oneshot};
use container::MutableMap;
use hashmap::{HashSet, HashSetMoveIterator};
use local_data;
use rt::in_green_task_context;
use rt::local::Local;
use rt::shouldnt_be_public::{Scheduler, KillHandle, WorkQueue, Thread, EventLoop};
use rt::sched::{Scheduler, Shutdown, TaskFromFriend};
use rt::task::{Task, Sched};
use rt::task::{UnwindReasonLinked, UnwindReasonStr};
use rt::task::{UnwindResult, Success, Failure};
use rt::uv::uvio::UvEventLoop;
use rt::thread::Thread;
use rt::work_queue::WorkQueue;
use rt::{in_green_task_context, new_event_loop, KillHandle};
use send_str::IntoSendStr;
use task::SingleThreaded;
use task::TaskOpts;
@ -617,8 +618,7 @@ pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) {
let work_queue = WorkQueue::new();
// Create a new scheduler to hold the new task
let new_loop = ~UvEventLoop::new() as ~EventLoop;
let mut new_sched = ~Scheduler::new_special(new_loop,
let mut new_sched = ~Scheduler::new_special(new_event_loop(),
work_queue,
(*sched).work_queues.clone(),
(*sched).sleeper_list.clone(),
@ -627,7 +627,7 @@ pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) {
let mut new_sched_handle = new_sched.make_handle();
// Allow the scheduler to exit when the pinned task exits
new_sched_handle.send_shutdown();
new_sched_handle.send(Shutdown);
// Pin the new task to the new scheduler
let new_task = if opts.watched {
@ -665,7 +665,7 @@ pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) {
debug!("enqueing join_task");
// Now tell the original scheduler to join with this thread
// by scheduling a thread-joining task on the original scheduler
orig_sched_handle.send_task_from_friend(join_task);
orig_sched_handle.send(TaskFromFriend(join_task));
// NB: We can't simply send a message from here to another task
// because this code isn't running in a task and message passing doesn't

View File

@ -37,7 +37,7 @@ a normal large stack.
*/
pub fn run_in_bare_thread(f: ~fn()) {
use cell::Cell;
use rt::shouldnt_be_public::Thread;
use rt::thread::Thread;
let f_cell = Cell::new(f);
let (port, chan) = comm::stream();