]> gitweb.factorcode.org Git - factor.git/commitdiff
Merge branch 'docs-linearization-typo' of http://github.com/mncharity/factor
authorSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Fri, 10 Sep 2010 03:33:11 +0000 (20:33 -0700)
committerSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Fri, 10 Sep 2010 03:33:11 +0000 (20:33 -0700)
96 files changed:
basis/bootstrap/image/download/download.factor
basis/bootstrap/image/image.factor [changed mode: 0644->0755]
basis/compiler/cfg/alias-analysis/alias-analysis-tests.factor
basis/compiler/cfg/alias-analysis/alias-analysis.factor
basis/compiler/cfg/dependence/dependence.factor
basis/compiler/cfg/finalization/finalization.factor
basis/compiler/cfg/optimizer/optimizer.factor
basis/compiler/cfg/write-barrier/write-barrier-tests.factor [new file with mode: 0644]
basis/compiler/cfg/write-barrier/write-barrier.factor
basis/compiler/tests/alien.factor
basis/compiler/tree/cleanup/cleanup-tests.factor
basis/cpu/x86/32/bootstrap.factor [changed mode: 0644->0755]
basis/cpu/x86/64/bootstrap.factor [changed mode: 0644->0755]
basis/debugger/debugger.factor [changed mode: 0644->0755]
basis/delegate/delegate-tests.factor
basis/delegate/delegate.factor
basis/ftp/server/server-tests.factor
basis/ftp/server/server.factor
basis/http/server/server.factor
basis/io/launcher/unix/unix-tests.factor
basis/io/servers/connection/connection.factor
basis/io/sockets/secure/secure.factor
basis/io/sockets/sockets-tests.factor
basis/io/sockets/sockets.factor
basis/io/sockets/unix/unix.factor
basis/io/sockets/windows/windows.factor
basis/io/streams/limited/limited-tests.factor
basis/io/streams/limited/limited.factor
basis/match/match-docs.factor
basis/math/floats/env/env-tests.factor
basis/mime/multipart/multipart.factor
basis/stack-checker/alien/alien.factor
basis/stack-checker/known-words/known-words.factor
basis/tools/disassembler/disassembler-docs.factor
basis/tools/time/time-docs.factor
basis/urls/secure/secure.factor
core/bootstrap/primitives.factor [changed mode: 0644->0755]
core/io/pathnames/pathnames.factor
extra/benchmark/sockets/sockets.factor
extra/geo-ip/geo-ip.factor
extra/irc/gitbot/gitbot.factor
extra/mason/build/build.factor
extra/mason/child/child.factor
extra/mason/common/common-tests.factor
extra/mason/common/common.factor
extra/mason/config/config.factor
extra/mason/disk/authors.txt [new file with mode: 0644]
extra/mason/disk/disk-tests.factor [new file with mode: 0644]
extra/mason/disk/disk.factor [new file with mode: 0644]
extra/mason/docs/docs.factor [new file with mode: 0644]
extra/mason/email/email.factor
extra/mason/git/authors.txt [new file with mode: 0644]
extra/mason/git/git.factor [new file with mode: 0644]
extra/mason/help/help.factor [deleted file]
extra/mason/mason.factor
extra/mason/notify/notify.factor
extra/mason/report/report.factor
extra/mason/server/server-tests.factor [new file with mode: 0644]
extra/mason/server/server.factor
extra/mason/updates/updates.factor
extra/twitter/twitter.factor
extra/webapps/mason/counter/counter.factor [new file with mode: 0644]
extra/webapps/mason/dashboard.xml [new file with mode: 0644]
extra/webapps/mason/dashboard/dashboard.factor [new file with mode: 0644]
extra/webapps/mason/docs-update/authors.txt [new file with mode: 0644]
extra/webapps/mason/docs-update/docs-update.factor [new file with mode: 0644]
extra/webapps/mason/download-package.xml
extra/webapps/mason/download-release.xml
extra/webapps/mason/downloads.xml
extra/webapps/mason/grids/grids.factor
extra/webapps/mason/increment-counter/increment-counter.factor [new file with mode: 0644]
extra/webapps/mason/make-release.xml [deleted file]
extra/webapps/mason/make-release/make-release.factor
extra/webapps/mason/mason.factor
extra/webapps/mason/status-update/status-update.factor
extra/webapps/mason/utils/utils.factor
extra/webapps/user-admin/user-admin.factor
extra/websites/concatenative/concatenative.factor
vm/aging_collector.cpp
vm/callstack.cpp
vm/compaction.cpp
vm/entry_points.cpp [changed mode: 0644->0755]
vm/entry_points.hpp [changed mode: 0644->0755]
vm/errors.cpp
vm/factor.cpp
vm/full_collector.cpp
vm/gc.cpp
vm/gc.hpp
vm/mach_signal.cpp [changed mode: 0644->0755]
vm/nursery_collector.cpp
vm/objects.hpp [changed mode: 0644->0755]
vm/os-unix.cpp [changed mode: 0644->0755]
vm/os-unix.hpp
vm/os-windows-nt.cpp
vm/to_tenured_collector.cpp
vm/vm.hpp

index 3a1abb3b2d0a300b5e3d67f7b247d2882c6cb5e4..eeaccd9347edcf00b5e382c74a44e3ffe9630fae 100644 (file)
@@ -10,13 +10,17 @@ CONSTANT: url URL" http://factorcode.org/images/latest/"
     url "checksums.txt" >url derive-url http-get nip
     string-lines [ " " split1 ] { } map>assoc ;
 
+: file-checksum ( image -- checksum )
+    md5 checksum-file hex-string ;
+
+: download-checksum ( image -- checksum )
+    download-checksums at ;
+
 : need-new-image? ( image -- ? )
     dup exists?
-    [
-        [ md5 checksum-file hex-string ]
-        [ download-checksums at ]
-        bi = not
-    ] [ drop t ] if ;
+    [ [ file-checksum ] [ download-checksum ] bi = not ]
+    [ drop t ]
+    if ;
 
 : verify-image ( image -- )
     need-new-image? [ "Boot image corrupt" throw ] when ;
old mode 100644 (file)
new mode 100755 (executable)
index 371902e..623b169
@@ -201,6 +201,8 @@ SPECIAL-OBJECT: jit-declare-word 41
 SPECIAL-OBJECT: c-to-factor-word 42
 SPECIAL-OBJECT: lazy-jit-compile-word 43
 SPECIAL-OBJECT: unwind-native-frames-word 44
+SPECIAL-OBJECT: fpu-state-word 45
+SPECIAL-OBJECT: set-fpu-state-word 46
 
 SPECIAL-OBJECT: callback-stub 48
 
@@ -540,6 +542,8 @@ M: quotation '
     \ c-to-factor c-to-factor-word set
     \ lazy-jit-compile lazy-jit-compile-word set
     \ unwind-native-frames unwind-native-frames-word set
+    \ fpu-state fpu-state-word set
+    \ set-fpu-state set-fpu-state-word set
     undefined-def undefined-quot set ;
 
 : emit-special-objects ( -- )
index adf5d61a253833a30c93faa46ad1d7648211b569..21241e6f4ad10507927a7aacbddfbace19160feb 100644 (file)
@@ -288,8 +288,8 @@ IN: compiler.cfg.alias-analysis.tests
     } test-alias-analysis
 ] unit-test
 
-! We can't make any assumptions about heap-ac between alien
-! calls, since they might callback into Factor code
+! We can't make any assumptions about heap-ac between
+! instructions which can call back into Factor code
 [
     V{
         T{ ##peek f 0 D 0 }
@@ -359,3 +359,90 @@ IN: compiler.cfg.alias-analysis.tests
         T{ ##set-slot-imm f 1 0 1 0 }
     } test-alias-analysis
 ] unit-test
+
+! We can't eliminate stores on any alias class across a GC-ing
+! instruction
+[
+    V{
+        T{ ##allot f 0 }
+        T{ ##slot-imm f 1 0 1 0 }
+        T{ ##alien-invoke f { } { } { } { } 0 0 "free" }
+        T{ ##copy f 2 1 any-rep }
+    }
+] [
+    V{
+        T{ ##allot f 0 }
+        T{ ##slot-imm f 1 0 1 0 }
+        T{ ##alien-invoke f { } { } { } { } 0 0 "free" }
+        T{ ##slot-imm f 2 0 1 0 }
+    } test-alias-analysis
+] unit-test
+
+[
+    V{
+        T{ ##allot f 0 }
+        T{ ##peek f 1 D 1 }
+        T{ ##set-slot-imm f 1 0 1 0 }
+        T{ ##alien-invoke f { } { } { } { } 0 0 "free" }
+        T{ ##copy f 2 1 any-rep }
+    }
+] [
+    V{
+        T{ ##allot f 0 }
+        T{ ##peek f 1 D 1 }
+        T{ ##set-slot-imm f 1 0 1 0 }
+        T{ ##alien-invoke f { } { } { } { } 0 0 "free" }
+        T{ ##slot-imm f 2 0 1 0 }
+    } test-alias-analysis
+] unit-test
+
+[
+    V{
+        T{ ##allot f 0 }
+        T{ ##peek f 1 D 1 }
+        T{ ##peek f 2 D 2 }
+        T{ ##set-slot-imm f 1 0 1 0 }
+        T{ ##alien-invoke f { } { } { } { } 0 0 "free" }
+        T{ ##set-slot-imm f 2 0 1 0 }
+    }
+] [
+    V{
+        T{ ##allot f 0 }
+        T{ ##peek f 1 D 1 }
+        T{ ##peek f 2 D 2 }
+        T{ ##set-slot-imm f 1 0 1 0 }
+        T{ ##alien-invoke f { } { } { } { } 0 0 "free" }
+        T{ ##set-slot-imm f 2 0 1 0 }
+    } test-alias-analysis
+] unit-test
+
+[
+    V{
+        T{ ##allot f 0 }
+        T{ ##slot-imm f 1 0 1 0 }
+        T{ ##alien-invoke f { } { } { } { } 0 0 "free" }
+    }
+] [
+    V{
+        T{ ##allot f 0 }
+        T{ ##slot-imm f 1 0 1 0 }
+        T{ ##alien-invoke f { } { } { } { } 0 0 "free" }
+        T{ ##set-slot-imm f 1 0 1 0 }
+    } test-alias-analysis
+] unit-test
+
+! Make sure that gc-map-insns which are also vreg-insns are
+! handled properly
+[
+    V{
+        T{ ##allot f 0 }
+        T{ ##alien-indirect f { } { } { { 2 double-rep 0 } } { } 0 0 "free" }
+        T{ ##set-slot-imm f 2 0 1 0 }
+    }
+] [
+    V{
+        T{ ##allot f 0 }
+        T{ ##alien-indirect f { } { } { { 2 double-rep 0 } } { } 0 0 "free" }
+        T{ ##set-slot-imm f 2 0 1 0 }
+    } test-alias-analysis
+] unit-test
index 5ba0bd1300a9b7e9e5f7be3caa082abc22bfa49c..6fff3f021678c9c8a55cec4d685780af7cea4e6a 100644 (file)
@@ -218,7 +218,7 @@ GENERIC: analyze-aliases ( insn -- insn' )
 
 M: insn analyze-aliases ;
 
-M: vreg-insn analyze-aliases
+: def-acs ( insn -- insn' )
     ! If an instruction defines a value with a non-integer
     ! representation it means that the value will be boxed
     ! anywhere its used as a tagged pointer. Boxing allocates
@@ -229,6 +229,9 @@ M: vreg-insn analyze-aliases
         [ set-heap-ac ] [ set-new-ac ] if
     ] each-def-rep ;
 
+M: vreg-insn analyze-aliases
+    def-acs ;
+
 M: ##phi analyze-aliases
     dup dst>> set-heap-ac ;
 
@@ -286,6 +289,29 @@ M: ##compare analyze-aliases
         analyze-aliases
     ] when ;
 
+: clear-live-slots ( -- )
+    heap-ac get ac>vregs [ live-slots get at clear-assoc ] each ;
+
+: clear-recent-stores ( -- )
+    recent-stores get values [ clear-assoc ] each ;
+
+M: gc-map-insn analyze-aliases
+    ! Can't use call-next-method here because of a limitation, gah
+    def-acs
+    clear-recent-stores ;
+
+M: factor-call-insn analyze-aliases
+    def-acs
+    clear-recent-stores
+    clear-live-slots ;
+
+GENERIC: eliminate-dead-stores ( insn -- ? )
+
+M: ##set-slot-imm eliminate-dead-stores
+    insn#>> dead-stores get in? not ;
+
+M: insn eliminate-dead-stores drop t ;
+
 : reset-alias-analysis ( -- )
     recent-stores get clear-assoc
     vregs>acs get clear-assoc
@@ -298,20 +324,6 @@ M: ##compare analyze-aliases
     \ ##vm-field set-new-ac
     \ ##alien-global set-new-ac ;
 
-M: factor-call-insn analyze-aliases
-    call-next-method
-    heap-ac get ac>vregs [
-        [ live-slots get at clear-assoc ]
-        [ recent-stores get at clear-assoc ] bi
-    ] each ;
-
-GENERIC: eliminate-dead-stores ( insn -- ? )
-
-M: ##set-slot-imm eliminate-dead-stores
-    insn#>> dead-stores get in? not ;
-
-M: insn eliminate-dead-stores drop t ;
-
 : alias-analysis-step ( insns -- insns' )
     reset-alias-analysis
     [ local-live-in [ set-heap-ac ] each ]
index d2e4a11c5111ea7dd917dcf06517cb50fea0ede6..54f308324a161f85f79000db8fc1abb1e929be90 100644 (file)
@@ -57,6 +57,7 @@ UNION: slot-insn
 UNION: memory-insn
     ##load-memory ##load-memory-imm
     ##store-memory ##store-memory-imm
+    ##write-barrier ##write-barrier-imm
     alien-call-insn
     slot-insn ;
 
index 2b731bdd904f49ae8994944872ec4c95366ba7b8..a0bb29cdf0da41335ed77f66d58a2c925adfa1b6 100644 (file)
@@ -2,15 +2,16 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel compiler.cfg.representations
 compiler.cfg.scheduling compiler.cfg.gc-checks
-compiler.cfg.save-contexts compiler.cfg.ssa.destruction
-compiler.cfg.build-stack-frame compiler.cfg.linear-scan
-compiler.cfg.stacks.uninitialized ;
+compiler.cfg.write-barrier compiler.cfg.save-contexts
+compiler.cfg.ssa.destruction compiler.cfg.build-stack-frame
+compiler.cfg.linear-scan compiler.cfg.stacks.uninitialized ;
 IN: compiler.cfg.finalization
 
 : finalize-cfg ( cfg -- cfg' )
     select-representations
     schedule-instructions
     insert-gc-checks
+    eliminate-write-barriers
     dup compute-uninitialized-sets
     insert-save-contexts
     destruct-ssa
index 5881cd78ea32280068d418b9bcc726d9882e050a..6a62b6f7e779920bb6d31f7fa82e74dbcd749ec1 100644 (file)
@@ -9,8 +9,7 @@ compiler.cfg.ssa.construction
 compiler.cfg.alias-analysis
 compiler.cfg.value-numbering
 compiler.cfg.copy-prop
-compiler.cfg.dce
-compiler.cfg.write-barrier ;
+compiler.cfg.dce ;
 IN: compiler.cfg.optimizer
 
 : optimize-cfg ( cfg -- cfg' )
@@ -23,5 +22,4 @@ IN: compiler.cfg.optimizer
     alias-analysis
     value-numbering
     copy-propagation
-    eliminate-dead-code
-    eliminate-write-barriers ;
+    eliminate-dead-code ;
diff --git a/basis/compiler/cfg/write-barrier/write-barrier-tests.factor b/basis/compiler/cfg/write-barrier/write-barrier-tests.factor
new file mode 100644 (file)
index 0000000..b11ffa8
--- /dev/null
@@ -0,0 +1,154 @@
+USING: compiler.cfg.instructions compiler.cfg.write-barrier
+tools.test ;
+IN: compiler.cfg.write-barrier.tests
+
+! Do need a write barrier on a random store.
+[
+    V{
+        T{ ##peek f 1 }
+        T{ ##set-slot f 2 1 3 }
+        T{ ##write-barrier f 1 3 }
+    }
+] [
+    V{
+        T{ ##peek f 1 }
+        T{ ##set-slot f 2 1 3 }
+        T{ ##write-barrier f 1 3 }
+    } write-barriers-step
+] unit-test
+
+[
+    V{
+        T{ ##peek f 1 }
+        T{ ##set-slot-imm f 2 1 }
+        T{ ##write-barrier-imm f 1 }
+    }
+] [
+    V{
+        T{ ##peek f 1 }
+        T{ ##set-slot-imm f 2 1 }
+        T{ ##write-barrier-imm f 1 }
+    } write-barriers-step
+] unit-test
+
+! Don't need a write barrier on freshly allocated objects.
+[
+    V{
+        T{ ##allot f 1 }
+        T{ ##set-slot f 2 1 3 }
+    }
+] [
+    V{
+        T{ ##allot f 1 }
+        T{ ##set-slot f 2 1 3 }
+        T{ ##write-barrier f 1 3 }
+    } write-barriers-step
+] unit-test
+
+[
+    V{
+        T{ ##allot f 1 }
+        T{ ##set-slot-imm f 2 1 }
+    }
+] [
+    V{
+        T{ ##allot f 1 }
+        T{ ##set-slot-imm f 2 1 }
+        T{ ##write-barrier-imm f 1 }
+    } write-barriers-step
+] unit-test
+
+! Do need a write barrier if there's a subroutine call between
+! the allocation and the store.
+[
+    V{
+        T{ ##allot f 1 }
+        T{ ##box }
+        T{ ##set-slot f 2 1 3 }
+        T{ ##write-barrier f 1 3 }
+    }
+] [
+    V{
+        T{ ##allot f 1 }
+        T{ ##box }
+        T{ ##set-slot f 2 1 3 }
+        T{ ##write-barrier f 1 3 }
+    } write-barriers-step
+] unit-test
+
+[
+    V{
+        T{ ##allot f 1 }
+        T{ ##box }
+        T{ ##set-slot-imm f 2 1 }
+        T{ ##write-barrier-imm f 1 }
+    }
+] [
+    V{
+        T{ ##allot f 1 }
+        T{ ##box }
+        T{ ##set-slot-imm f 2 1 }
+        T{ ##write-barrier-imm f 1 }
+    } write-barriers-step
+] unit-test
+
+! ##copy instructions
+[
+    V{
+        T{ ##copy f 2 1 }
+        T{ ##set-slot-imm f 3 1 }
+        T{ ##write-barrier-imm f 2 }
+    }
+] [
+    V{
+        T{ ##copy f 2 1 }
+        T{ ##set-slot-imm f 3 1 }
+        T{ ##write-barrier-imm f 2 }
+    } write-barriers-step
+] unit-test
+
+[
+    V{
+        T{ ##copy f 2 1 }
+        T{ ##set-slot-imm f 3 2 }
+        T{ ##write-barrier-imm f 1 }
+    }
+] [
+    V{
+        T{ ##copy f 2 1 }
+        T{ ##set-slot-imm f 3 2 }
+        T{ ##write-barrier-imm f 1 }
+    } write-barriers-step
+] unit-test
+
+[
+    V{
+        T{ ##copy f 2 1 }
+        T{ ##copy f 3 2 }
+        T{ ##set-slot-imm f 3 1 }
+        T{ ##write-barrier-imm f 2 }
+    }
+] [
+    V{
+        T{ ##copy f 2 1 }
+        T{ ##copy f 3 2 }
+        T{ ##set-slot-imm f 3 1 }
+        T{ ##write-barrier-imm f 2 }
+    } write-barriers-step
+] unit-test
+
+[
+    V{
+        T{ ##copy f 2 1 }
+        T{ ##copy f 3 2 }
+        T{ ##set-slot-imm f 4 1 }
+        T{ ##write-barrier-imm f 3 }
+    }
+] [
+    V{
+        T{ ##copy f 2 1 }
+        T{ ##copy f 3 2 }
+        T{ ##set-slot-imm f 4 1 }
+        T{ ##write-barrier-imm f 3 }
+    } write-barriers-step
+] unit-test
index a34bf6c07f4e0477664add53265d2c284e67a507..6f8e437aa908b86a4e569ad875e8640b6c9124cc 100644 (file)
@@ -6,23 +6,39 @@ sequences sets ;
 FROM: namespaces => set ;
 IN: compiler.cfg.write-barrier
 
+! This pass must run after GC check insertion and scheduling.
+
 SYMBOL: fresh-allocations
 
 SYMBOL: mutated-objects
 
+SYMBOL: copies
+
+: resolve-copy ( src -- dst )
+    copies get ?at drop ;
+
 GENERIC: eliminate-write-barrier ( insn -- ? )
 
+: fresh-allocation ( vreg -- )
+    fresh-allocations get conjoin ;
+
 M: ##allot eliminate-write-barrier
-    dst>> fresh-allocations get conjoin t ;
+    dst>> fresh-allocation t ;
+
+: mutated-object ( vreg -- )
+    resolve-copy mutated-objects get conjoin ;
 
 M: ##set-slot eliminate-write-barrier
-    obj>> mutated-objects get conjoin t ;
+    obj>> mutated-object t ;
 
 M: ##set-slot-imm eliminate-write-barrier
-    obj>> mutated-objects get conjoin t ;
+    obj>> mutated-object t ;
 
 : needs-write-barrier? ( insn -- ? )
-    { [ fresh-allocations get key? not ] [ mutated-objects get key? ] } 1&& ;
+    resolve-copy {
+        [ fresh-allocations get key? not ]
+        [ mutated-objects get key? ]
+    } 1&& ;
 
 M: ##write-barrier eliminate-write-barrier
     src>> needs-write-barrier? ;
@@ -30,14 +46,18 @@ M: ##write-barrier eliminate-write-barrier
 M: ##write-barrier-imm eliminate-write-barrier
     src>> needs-write-barrier? ;
 
+M: gc-map-insn eliminate-write-barrier
+    fresh-allocations get clear-assoc ;
+
 M: ##copy eliminate-write-barrier
-    "Run copy propagation first" throw ;
+    [ src>> resolve-copy ] [ dst>> ] bi copies get set-at t ;
 
 M: insn eliminate-write-barrier drop t ;
 
 : write-barriers-step ( insns -- insns' )
     H{ } clone fresh-allocations set
     H{ } clone mutated-objects set
+    H{ } clone copies set
     [ eliminate-write-barrier ] filter! ;
 
 : eliminate-write-barriers ( cfg -- cfg )
index 60e132bb76531ad0b7d0a96ea695333cb2d77cfb..65e67e66d2f593a1bfcd2648923e29716cb2a6c0 100755 (executable)
@@ -823,3 +823,25 @@ TUPLE: some-tuple x ;
         aa-indirect-1 >>x
     ] compile-call
 ] unit-test
+
+! Write barrier elimination was being done before scheduling and
+! GC check insertion, and didn't take subroutine calls into
+! account. Oops...
+: write-barrier-elim-in-wrong-place ( -- obj )
+    ! A callback used below
+    void { } cdecl [ compact-gc ] alien-callback
+    ! Allocate an object A in the nursery
+    1 f <array>
+    ! Subroutine call promotes the object to tenured
+    swap void { } cdecl alien-indirect
+    ! Allocate another object B in the nursery, store it into
+    ! the first
+    1 f <array> over set-first
+    ! Now object A's card should be marked and minor GC should
+    ! promote B to aging
+    minor-gc
+    ! Do stuff
+    [ 100 [ ] times ] infer.
+    ;
+
+[ { { f } } ] [ write-barrier-elim-in-wrong-place ] unit-test
index 2c5c469201708b6186e795a63830d1373ac7e2ec..88e7895c896b514f2948a8ff64349f6bd6114795 100644 (file)
@@ -541,3 +541,8 @@ USING: alien alien.c-types ;
     [ char { char char } cdecl [ + ] alien-callback ]
     \ fixnum+fast inlined?
 ] unit-test
+
+[ t ] [
+    [ void { } cdecl [ ] alien-callback void { } cdecl alien-indirect ]
+    \ >c-ptr inlined?
+] unit-test
old mode 100644 (file)
new mode 100755 (executable)
index 5eb25fc..9548171
@@ -64,9 +64,6 @@ IN: bootstrap.x86
     ds-reg ctx-reg context-datastack-offset [+] MOV
     rs-reg ctx-reg context-retainstack-offset [+] MOV ;
 
-: jit-scrub-return ( n -- )
-    ESP swap [+] 0 MOV ;
-
 [
     ! ctx-reg is preserved across the call because it is non-volatile
     ! in the C ABI
@@ -115,24 +112,28 @@ IN: bootstrap.x86
     ! Windows-specific setup
     ctx-reg jit-update-seh
 
-    ! Clear x87 stack, but preserve rounding mode and exception flags
-    ESP 2 SUB
-    ESP [] FNSTCW
-    FNINIT
-    ESP [] FLDCW
-    ESP 2 ADD
-
     ! Load arguments
     EAX ESP stack-frame-size [+] MOV
     EDX ESP stack-frame-size 4 + [+] MOV
 
     ! Unwind stack frames
     ESP EDX MOV
-    0 jit-scrub-return
 
     jit-jump-quot
 ] \ unwind-native-frames define-sub-primitive
 
+[
+    ESP 2 SUB
+    ESP [] FNSTCW
+    FNINIT
+    AX ESP [] MOV
+    ESP 2 ADD
+] \ fpu-state define-sub-primitive
+
+[
+    ESP stack-frame-size [+] FLDCW
+] \ set-fpu-state define-sub-primitive
+
 [
     ! Load callstack object
     temp3 ds-reg [] MOV
@@ -251,7 +252,9 @@ IN: bootstrap.x86
 
 ! Contexts
 : jit-switch-context ( reg -- )
-    -4 jit-scrub-return
+    ! Reset return value since its bogus right now, to avoid
+    ! confusing the GC
+    ESP -4 [+] 0 MOV
 
     ! Make the new context the current one
     ctx-reg swap MOV
old mode 100644 (file)
new mode 100755 (executable)
index d491354..f3de6b9
@@ -62,9 +62,6 @@ IN: bootstrap.x86
     ds-reg ctx-reg context-datastack-offset [+] MOV
     rs-reg ctx-reg context-retainstack-offset [+] MOV ;
 
-: jit-scrub-return ( n -- )
-    RSP swap [+] 0 MOV ;
-
 [
     ! ctx-reg is preserved across the call because it is non-volatile
     ! in the C ABI
@@ -102,15 +99,8 @@ IN: bootstrap.x86
 \ (call) define-combinator-primitive
 
 [
-    ! Clear x87 stack, but preserve rounding mode and exception flags
-    RSP 2 SUB
-    RSP [] FNSTCW
-    FNINIT
-    RSP [] FLDCW
-
     ! Unwind stack frames
     RSP arg2 MOV
-    0 jit-scrub-return
 
     ! Load VM pointer into vm-reg, since we're entering from
     ! C code
@@ -124,6 +114,21 @@ IN: bootstrap.x86
     jit-jump-quot
 ] \ unwind-native-frames define-sub-primitive
 
+[
+    RSP 2 SUB
+    RSP [] FNSTCW
+    FNINIT
+    AX RSP [] MOV
+    RSP 2 ADD
+] \ fpu-state define-sub-primitive
+
+[
+    RSP 2 SUB
+    RSP [] arg1 16-bit-version-of MOV
+    RSP [] FLDCW
+    RSP 2 ADD
+] \ set-fpu-state define-sub-primitive
+
 [
     ! Load callstack object
     arg4 ds-reg [] MOV
@@ -228,7 +233,9 @@ IN: bootstrap.x86
 
 ! Contexts
 : jit-switch-context ( reg -- )
-    -8 jit-scrub-return
+    ! Reset return value since its bogus right now, to avoid
+    ! confusing the GC
+    RSP -8 [+] 0 MOV
 
     ! Make the new context the current one
     ctx-reg swap MOV
old mode 100644 (file)
new mode 100755 (executable)
index eca34c2..9159b7f
@@ -136,7 +136,7 @@ PREDICATE: vm-error < array
     {
         { [ dup empty? ] [ drop f ] }
         { [ dup first "kernel-error" = not ] [ drop f ] }
-        [ second 0 16 between? ]
+        [ second 0 17 between? ]
     } cond ;
 
 : vm-errors ( error -- n errors )
index 4a280ef58432998b1fc5246ee20c6c2c619cd5b3..4d42f71dc03a40407ddcfeac3347fa19c1981ec8 100644 (file)
@@ -93,6 +93,17 @@ CONSULT: slot-protocol-test-2 slot-protocol-test-3 d>> ;
     [ a>> ] [ b>> ] [ c>> ] tri
 ] unit-test
 
+TUPLE: slot-protocol-test-4 { x read-only } ;
+
+TUPLE: slot-protocol-test-5 { a-read-only-slot read-only } ;
+
+CONSULT: slot-protocol-test-5 slot-protocol-test-4 x>> ;
+
+[ "hey" ] [
+    "hey" slot-protocol-test-5 boa slot-protocol-test-4 boa
+    a-read-only-slot>>
+] unit-test
+
 GENERIC: do-me ( x -- )
 
 M: f do-me drop ;
index ebd6a05b482c30025bb246d3c4a17549f516c866..cdd58afc9e360f7745260211d4c639d2755bba5c 100644 (file)
@@ -4,7 +4,7 @@
 USING: accessors arrays assocs classes.tuple definitions effects generic
 generic.standard hashtables kernel lexer math parser
 generic.parser sequences sets slots words words.symbol fry
-compiler.units ;
+compiler.units make ;
 IN: delegate
 
 ERROR: broadcast-words-must-have-no-outputs group ;
@@ -22,13 +22,16 @@ GENERIC: group-words ( group -- words )
 M: standard-generic group-words
     dup "combination" word-prop #>> 2array 1array ;
 
-: slot-group-words ( slots -- words )
+: slot-words, ( slot-spec -- )
+    [ name>> reader-word 0 2array , ]
     [
-        name>>
-        [ reader-word 0 2array ]
-        [ writer-word 0 2array ] bi
-        2array
-    ] map concat ;
+        dup read-only>> [ drop ] [
+            name>> writer-word 0 2array ,
+        ] if
+    ] bi ;
+
+: slot-group-words ( slots -- words )
+    [ [ slot-words, ] each ] { } make ;
 
 M: tuple-class group-words
     all-slots slot-group-words ;
index 2572f36cb0ef902741b54074618be6fb4dd4ad51..585728dff609555702bc00afe7491fe5c4a971c4 100644 (file)
@@ -25,7 +25,7 @@ IN: ftp.server.tests
                 "ftp" >>protocol
                 "localhost" >>host
                 create-test-file >>path
-                _ call
+                @
         ]
         [ stop-server ] tri
     ] with-unique-directory drop ; inline
index 73de439a0153b8b74b9afe9a1687fccbdb4f220b..8fb0c1604395f07755492398f638a2113f0c9ff0 100644 (file)
@@ -1,14 +1,14 @@
 ! Copyright (C) 2008 Doug Coleman.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: accessors assocs byte-arrays calendar classes combinators
+USING: accessors calendar calendar.format classes combinators
 combinators.short-circuit concurrency.promises continuations
-destructors ftp io io.backend io.directories io.encodings
-io.encodings.binary tools.files io.encodings.utf8 io.files
-io.files.info io.pathnames io.servers.connection io.sockets
-io.streams.duplex io.streams.string io.timeouts kernel make math
-math.bitwise math.parser namespaces sequences splitting threads
-unicode.case logging calendar.format strings io.files.links
-io.files.types io.encodings.8-bit.latin1 simple-tokenizer ;
+destructors ftp io io.directories io.encodings
+io.encodings.8-bit.latin1 io.encodings.binary io.encodings.utf8
+io.files io.files.info io.files.types io.pathnames
+io.servers.connection io.sockets io.streams.string io.timeouts
+kernel logging math math.bitwise math.parser namespaces
+sequences simple-tokenizer splitting strings threads
+tools.files unicode.case ;
 IN: ftp.server
 
 SYMBOL: server
@@ -49,6 +49,17 @@ C: <ftp-disconnect> ftp-disconnect
     [ but-last-slice [ "-" (send-response) ] with each ]
     [ first " " (send-response) ] 2bi ;
 
+: make-path-relative? ( path -- ? )
+    {
+        [ absolute-path? ]
+        [ drop server get serving-directory>> ]
+    } 1&& ;
+
+: fixup-relative-path ( string -- string' )
+    dup make-path-relative? [
+        [ server get serving-directory>> ] dip append-relative-path
+    ] when ;
+
 : server-response ( string n -- )
     2dup number>string swap ":" glue \ server-response DEBUG log-message
     <ftp-response>
@@ -115,14 +126,18 @@ ERROR: type-error type ;
     ] recover ;
 
 : random-local-server ( -- server )
-    remote-address get class new 0 >>port binary <server> ;
+    remote-address get class new binary <server> ;
 
 : port>bytes ( port -- hi lo )
     [ -8 shift ] keep [ 8 bits ] bi@ ;
 
+: display-directory ( -- string )
+    current-directory get server get serving-directory>> swap ?head drop
+    [ "/" ] when-empty ;
+
 : handle-PWD ( obj -- )
     drop
-    current-directory get "\"" dup surround 257 server-response ;
+    display-directory get "\"" dup surround 257 server-response ;
 
 : handle-SYST ( obj -- )
     drop
@@ -167,8 +182,9 @@ GENERIC: handle-passive-command ( stream obj -- )
 M: ftp-list handle-passive-command ( stream obj -- )
     drop
     start-directory [
-        utf8 encode-output
-        [ current-directory get directory. ] with-string-writer string-lines
+        utf8 encode-output [
+            current-directory get directory.
+        ] with-string-writer string-lines
         harvest [ ftp-send ] each
     ] with-output-stream finish-directory ;
 
@@ -225,6 +241,7 @@ M: ftp-disconnect handle-passive-command ( stream obj -- )
 
 : handle-RETR ( obj -- )
     tokenized>> second
+    fixup-relative-path
     dup can-serve-file? [
         <ftp-get> fulfill-client
     ] [
@@ -261,6 +278,7 @@ M: ftp-disconnect handle-passive-command ( stream obj -- )
 
 : handle-MDTM ( obj -- )
     tokenized>> 1 swap ?nth [
+        fixup-relative-path
         dup file-info dup directory? [
             drop not-a-plain-file
         ] [
@@ -283,6 +301,7 @@ ERROR: no-directory-permissions ;
 
 : handle-CWD ( obj -- )
     tokenized>> 1 swap ?nth [
+        fixup-relative-path
         dup can-serve-directory? [
             set-current-directory
             directory-change-success
@@ -350,3 +369,5 @@ M: ftp-server handle-client* ( server -- )
     <ftp-server> start-server ;
 
 ! sudo tcpdump -i en1 -A -s 10000  tcp port 21
+! [2010-09-04T22:07:58-05:00] DEBUG server-response: 500:Unrecognized command: EPRT |2|0:0:0:0:0:0:0:1|59359|
+
index ca838cb7fb8f5c8c21ea5af0cabb2e184d9ec3f4..637b4b3237f2d5b69b5379b0c9131e3e43335196 100644 (file)
@@ -49,12 +49,19 @@ ERROR: no-boundary ;
     ";" split1 nip
     "=" split1 nip [ no-boundary ] unless* ;
 
+SYMBOL: request-limit
+
+request-limit [ 64 1024 * ] initialize
+
 SYMBOL: upload-limit
 
+upload-limit [ 200,000,000 ] initialize
+
 : read-multipart-data ( request -- mime-parts )
     [ "content-type" header ]
     [ "content-length" header string>number ] bi
-    upload-limit get min limited-input
+    unlimited-input
+    upload-limit get [ min ] when* limited-input
     binary decode-input
     parse-multipart-form-data parse-multipart ;
  
@@ -276,14 +283,10 @@ LOG: httpd-benchmark DEBUG
 
 TUPLE: http-server < threaded-server ;
 
-SYMBOL: request-limit
-
-request-limit [ 64 1024 * ] initialize
-
 M: http-server handle-client*
     drop [
-        request-limit get limited-input
         ?refresh-all
+        request-limit get limited-input
         [ read-request ] ?benchmark
         [ do-request ] ?benchmark
         [ do-response ] ?benchmark
index fef6b076ba2f9890a739ec403df326a6709575fc..4f6615ca5bbdb4fb1797da99753dbc623fbd1ff0 100644 (file)
@@ -3,7 +3,8 @@ USING: io.files io.files.temp io.directories io.pathnames
 tools.test io.launcher arrays io namespaces continuations math
 io.encodings.binary io.encodings.ascii accessors kernel
 sequences io.encodings.utf8 destructors io.streams.duplex locals
-concurrency.promises threads unix.process calendar unix ;
+concurrency.promises threads unix.process calendar unix
+unix.process debugger.unix io.timeouts io.launcher.unix ;
 
 [ ] [
     [ "launcher-test-1" temp-file delete-file ] ignore-errors
@@ -138,3 +139,22 @@ concurrency.promises threads unix.process calendar unix ;
         s 3 seconds ?promise-timeout 0 =
     ]
 ] unit-test
+
+! Make sure that subprocesses don't inherit our signal mask
+
+! First, ensure that the Factor VM ignores SIGPIPE
+: send-sigpipe ( pid -- )
+    "SIGPIPE" signal-names index 1 +
+    kill io-error ;
+
+[ ] [ current-process-handle send-sigpipe ] unit-test
+
+! Spawn a process
+[ T{ signal f 13 } ] [
+    "sleep 1000" run-detached
+    1 seconds sleep
+    [ handle>> send-sigpipe ]
+    [ 2 seconds swap set-timeout ]
+    [ wait-for-process ]
+    tri
+] unit-test
index 4dfdc13bc93933ece11ff9b52ce2f8b9d13cd34b..494ce02d8abb48bf91a863fac4f25d97729e4061 100644 (file)
@@ -55,7 +55,7 @@ GENERIC: handle-client* ( threaded-server -- )
 
 : listen-on ( threaded-server -- addrspecs )
     [ secure>> >secure ] [ insecure>> >insecure ] bi
-    [ resolve-host ] bi@ append ;
+    [ dup [ resolve-host ] when ] bi@ append ;
 
 : accepted-connection ( remote local -- )
     [
index 9f7a4f822f054ef918fd728032c81ddb01d4f736..fbbea7c4c310ccf3158d2ae5695638ff56494a79 100644 (file)
@@ -39,7 +39,7 @@ HOOK: <secure-context> secure-socket-backend ( config -- context )
         with-disposal
     ] with-scope ; inline
 
-TUPLE: secure addrspec ;
+TUPLE: secure { addrspec read-only } ;
 
 C: <secure> secure
 
index 96ffbc5e180f840ec68b7cb0d6a5a59c51cdbae6..56939f484f406cac146b26a20fdec386a688a150 100644 (file)
@@ -58,7 +58,29 @@ io.streams.string ;
 [ "2001:6f8:37a:5:0:0:0:1" ]
 [ "2001:6f8:37a:5::1" T{ inet6 } [ inet-pton ] [ inet-ntop ] bi ] unit-test
 
-[ t ] [ "localhost" 80 <inet> resolve-host length 1 >= ] unit-test
+[ t t ] [
+    "localhost" 80 <inet> resolve-host
+    [ length 1 >= ]
+    [ [ [ inet4? ] [ inet6? ] bi or ] all? ] bi
+] unit-test
+
+[ t t ] [
+    "localhost" resolve-host
+    [ length 1 >= ]
+    [ [ [ ipv4? ] [ ipv6? ] bi or ] all? ] bi
+] unit-test
+
+[ t t ] [
+    f resolve-host
+    [ length 1 >= ]
+    [ [ [ ipv4? ] [ ipv6? ] bi or ] all? ] bi
+] unit-test
+
+[ t t ] [
+    f 0 <inet> resolve-host
+    [ length 1 >= ]
+    [ [ [ ipv4? ] [ ipv6? ] bi or ] all? ] bi
+] unit-test
 
 ! Smoke-test UDP
 [ ] [ "127.0.0.1" 0 <inet4> <datagram> "datagram1" set ] unit-test
@@ -107,3 +129,6 @@ io.streams.string ;
         "hi\n" write flush readln readln
     ] with-client
 ] unit-test
+
+! Binding to all interfaces should work
+[ ] [ f 0 <inet4> <datagram> dispose ] unit-test
index a1260e80bea712ca1c0015dd540759bf15b0db9c..30449f066f3908907df8898d4fb0496c3cf89cb9 100644 (file)
@@ -1,4 +1,4 @@
-! Copyright (C) 2007, 2008 Slava Pestov, Doug Coleman,
+! Copyright (C) 2007, 2010 Slava Pestov, Doug Coleman,
 ! Daniel Ehrenberg.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: generic kernel io.backend namespaces continuations sequences
@@ -6,7 +6,7 @@ arrays io.encodings io.ports io.streams.duplex io.encodings.ascii
 alien.strings io.binary accessors destructors classes byte-arrays
 parser alien.c-types math.parser splitting grouping math assocs
 summary system vocabs.loader combinators present fry vocabs.parser
-classes.struct alien.data ;
+classes.struct alien.data strings ;
 IN: io.sockets
 
 << {
@@ -17,6 +17,8 @@ IN: io.sockets
 ! Addressing
 <PRIVATE
 
+UNION: ?string string POSTPONE: f ;
+
 GENERIC: protocol-family ( addrspec -- af )
 
 GENERIC: sockaddr-size ( addrspec -- n )
@@ -31,6 +33,8 @@ GENERIC: inet-ntop ( data addrspec -- str )
 
 GENERIC: inet-pton ( str addrspec -- data )
 
+GENERIC# with-port 1 ( addrspec port -- addrspec )
+
 : make-sockaddr/size ( addrspec -- sockaddr size )
     [ make-sockaddr ] [ sockaddr-size ] bi ;
 
@@ -39,80 +43,88 @@ GENERIC: inet-pton ( str addrspec -- data )
 
 GENERIC: parse-sockaddr ( sockaddr addrspec -- newaddrspec )
 
+M: f parse-sockaddr nip ;
+
 HOOK: sockaddr-of-family os ( alien af -- sockaddr )
 
 HOOK: addrspec-of-family os ( af -- addrspec )
 
 PRIVATE>
 
-TUPLE: abstract-inet host port ;
-
-M: abstract-inet present
-    [ host>> ":" ] [ port>> number>string ] bi 3append ;
-
-TUPLE: local path ;
+TUPLE: local { path read-only } ;
 
 : <local> ( path -- addrspec )
     normalize-path local boa ;
 
 M: local present path>> "Unix domain socket: " prepend ;
 
-TUPLE: inet4 < abstract-inet ;
+SLOT: port
 
-C: <inet4> inet4
+TUPLE: ipv4 { host ?string read-only } ;
+
+C: <ipv4> ipv4
 
-M: inet4 inet-ntop ( data addrspec -- str )
+M: ipv4 inet-ntop ( data addrspec -- str )
     drop 4 memory>byte-array [ number>string ] { } map-as "." join ;
 
-ERROR: malformed-inet4 sequence ;
-ERROR: bad-inet4-component string ;
+<PRIVATE
 
-: parse-inet4 ( string -- seq )
-    "." split dup length 4 = [
-        malformed-inet4
-    ] unless
-    [
-        string>number
-        [ "Dotted component not a number" throw ] unless*
-    ] B{ } map-as ;
+ERROR: malformed-ipv4 sequence ;
 
-ERROR: invalid-inet4 string reason ;
+ERROR: bad-ipv4-component string ;
 
-M: invalid-inet4 summary drop "Invalid IPv4 address" ;
+: parse-ipv4 ( string -- seq )
+    "." split dup length 4 = [ malformed-ipv4 ] unless
+    [ dup string>number [ ] [ bad-ipv4-component ] ?if ] B{ } map-as ;
 
-M: inet4 inet-pton ( str addrspec -- data )
-    drop
-    [ parse-inet4 ] [ invalid-inet4 ] recover ;
+ERROR: invalid-ipv4 string reason ;
+
+M: invalid-ipv4 summary drop "Invalid IPv4 address" ;
+
+PRIVATE>
+
+M: ipv4 inet-pton ( str addrspec -- data )
+    drop [ parse-ipv4 ] [ invalid-ipv4 ] recover ;
 
-M: inet4 address-size drop 4 ;
+M: ipv4 address-size drop 4 ;
 
-M: inet4 protocol-family drop PF_INET ;
+M: ipv4 protocol-family drop PF_INET ;
 
-M: inet4 sockaddr-size drop sockaddr-in heap-size ;
+M: ipv4 sockaddr-size drop sockaddr-in heap-size ;
 
-M: inet4 empty-sockaddr drop sockaddr-in <struct> ;
+M: ipv4 empty-sockaddr drop sockaddr-in <struct> ;
 
-M: inet4 make-sockaddr ( inet -- sockaddr )
+M: ipv4 make-sockaddr ( inet -- sockaddr )
     sockaddr-in <struct>
         AF_INET >>family
-        swap [ port>> htons >>port ]
-            [ host>> "0.0.0.0" or ]
-            [ inet-pton *uint >>addr ] tri ;
+        swap
+        [ port>> htons >>port ]
+        [ host>> "0.0.0.0" or ]
+        [ inet-pton *uint >>addr ] tri ;
+
+M: ipv4 parse-sockaddr ( sockaddr-in addrspec -- newaddrspec )
+    [ addr>> <uint> ] dip inet-ntop <ipv4> ;
+
+TUPLE: inet4 < ipv4 { port integer read-only } ;
+
+C: <inet4> inet4
+
+M: ipv4 with-port [ host>> ] dip <inet4> ;
 
 M: inet4 parse-sockaddr ( sockaddr-in addrspec -- newaddrspec )
-    [ [ addr>> <uint> ] dip inet-ntop ]
-    [ drop port>> ntohs ] 2bi <inet4> ;
+    [ call-next-method ] [ drop port>> ntohs ] 2bi with-port ;
 
-TUPLE: inet6 < abstract-inet ;
+M: inet4 present
+    [ host>> ] [ port>> number>string ] bi ":" glue ;
 
-C: <inet6> inet6
+TUPLE: ipv6 { host ?string read-only } ;
 
-M: inet6 inet-ntop ( data addrspec -- str )
-    drop 16 memory>byte-array 2 <groups> [ be> >hex ] map ":" join ;
+C: <ipv6> ipv6
 
-ERROR: invalid-inet6 string reason ;
+M: ipv6 inet-ntop ( data addrspec -- str )
+    drop 16 memory>byte-array 2 <groups> [ be> >hex ] map ":" join ;
 
-M: invalid-inet6 summary drop "Invalid IPv6 address" ;
+ERROR: invalid-ipv6 string reason ;
 
 <PRIVATE
 
@@ -120,55 +132,67 @@ ERROR: bad-ipv6-component obj ;
 
 ERROR: bad-ipv4-embedded-prefix obj ;
 
+ERROR: more-than-8-components ;
+
 : parse-ipv6-component ( seq -- seq' )
     [ dup hex> [ nip ] [ bad-ipv6-component ] if* ] { } map-as ;
 
-: parse-inet6 ( string -- seq )
+: parse-ipv6 ( string -- seq )
     [ f ] [
         ":" split CHAR: . over last member? [
             unclip-last
-            [ parse-ipv6-component ] [ parse-inet4 ] bi* append
+            [ parse-ipv6-component ] [ parse-ipv4 ] bi* append
         ] [
             parse-ipv6-component
         ] if
     ] if-empty ;
 
-: pad-inet6 ( string1 string2 -- seq )
+: pad-ipv6 ( string1 string2 -- seq )
     2dup [ length ] bi@ + 8 swap -
-    dup 0 < [ "More than 8 components" throw ] when
+    dup 0 < [ more-than-8-components ] when
     <byte-array> glue ;
 
-: inet6-bytes ( seq -- bytes )
+: ipv6-bytes ( seq -- bytes )
     [ 2 >be ] { } map-as B{ } concat-as ;
 
 PRIVATE>
 
-M: inet6 inet-pton ( str addrspec -- data )
+M: ipv6 inet-pton ( str addrspec -- data )
     drop
-    [
-        "::" split1 [ parse-inet6 ] bi@ pad-inet6 inet6-bytes
-    ] [ invalid-inet6 ] recover ;
+    [ "::" split1 [ parse-ipv6 ] bi@ pad-ipv6 ipv6-bytes ]
+    [ invalid-ipv6 ]
+    recover ;
 
-M: inet6 address-size drop 16 ;
+M: ipv6 address-size drop 16 ;
 
-M: inet6 protocol-family drop PF_INET6 ;
+M: ipv6 protocol-family drop PF_INET6 ;
 
-M: inet6 sockaddr-size drop sockaddr-in6 heap-size ;
+M: ipv6 sockaddr-size drop sockaddr-in6 heap-size ;
 
-M: inet6 empty-sockaddr drop sockaddr-in6 <struct> ;
+M: ipv6 empty-sockaddr drop sockaddr-in6 <struct> ;
 
-M: inet6 make-sockaddr ( inet -- sockaddr )
+M: ipv6 make-sockaddr ( inet -- sockaddr )
     sockaddr-in6 <struct>
         AF_INET6 >>family
-        swap [ port>> htons >>port ]
-            [ host>> "::" or ]
-            [ inet-pton >>addr ] tri ;
+        swap
+        [ port>> htons >>port ]
+        [ host>> "::" or ]
+        [ inet-pton >>addr ] tri ;
+
+M: ipv6 parse-sockaddr
+    [ addr>> ] dip inet-ntop <ipv6> ;
+
+TUPLE: inet6 < ipv6 { port integer read-only } ;
+
+C: <inet6> inet6
+
+M: ipv6 with-port [ host>> ] dip <inet6> ;
 
 M: inet6 parse-sockaddr
-    [ [ addr>> ] dip inet-ntop ]
-    [ drop port>> ntohs ] 2bi <inet6> ;
+    [ call-next-method ] [ drop port>> ntohs ] 2bi with-port ;
 
-M: f parse-sockaddr nip ;
+M: inet6 present
+    [ host>> ] [ port>> number>string ] bi ":" glue ;
 
 <PRIVATE
 
@@ -247,17 +271,11 @@ HOOK: (send) io-backend ( packet addrspec datagram -- )
 
 HOOK: addrinfo-error io-backend ( n -- )
 
-: resolve-passive-host ( -- addrspecs )
-    { T{ inet6 f "::" f } T{ inet4 f "0.0.0.0" f } } [ clone ] map ;
-
 : prepare-addrinfo ( -- addrinfo )
     addrinfo <struct>
         PF_UNSPEC >>family
         IPPROTO_TCP >>protocol ;
 
-: fill-in-ports ( addrspecs port -- addrspecs )
-    '[ _ >>port ] map ;
-
 PRIVATE>
 
 : <client> ( remote encoding -- stream local )
@@ -306,21 +324,34 @@ SYMBOL: remote-address
 
 GENERIC: resolve-host ( addrspec -- seq )
 
-TUPLE: inet < abstract-inet ;
+TUPLE: hostname { host ?string read-only } ;
+
+TUPLE: inet < hostname port ;
+
+M: inet present
+    [ host>> ] [ port>> number>string ] bi ":" glue ;
 
 C: <inet> inet
 
+M: string resolve-host
+    f prepare-addrinfo f <void*>
+    [ getaddrinfo addrinfo-error ] keep *void* addrinfo memory>struct
+    [ parse-addrinfo-list ] keep freeaddrinfo ;
+
+M: hostname resolve-host
+    host>> resolve-host ;
+
 M: inet resolve-host
-    [ port>> ] [ host>> ] bi [
-        f prepare-addrinfo f <void*>
-        [ getaddrinfo addrinfo-error ] keep *void* addrinfo memory>struct
-        [ parse-addrinfo-list ] keep freeaddrinfo
-    ] [ resolve-passive-host ] if*
-    swap fill-in-ports ;
+    [ call-next-method ] [ port>> ] bi '[ _ with-port ] map ;
+
+M: inet4 resolve-host 1array ;
+
+M: inet6 resolve-host 1array ;
 
-M: f resolve-host drop { } ;
+M: local resolve-host 1array ;
 
-M: object resolve-host 1array ;
+M: f resolve-host
+    drop { T{ ipv6 f "::" } T{ ipv4 f "0.0.0.0" } } ;
 
 : host-name ( -- string )
     256 <byte-array> dup dup length gethostname
index cc0740500a766f490a395188a9b78f2d27d78bf8..9613ce4f4028dba5377146c14a5a9e5fee553f24 100644 (file)
@@ -32,8 +32,8 @@ M: unix sockaddr-of-family ( alien af -- addrspec )
 
 M: unix addrspec-of-family ( af -- addrspec )
     {
-        { AF_INET [ T{ inet4 } ] }
-        { AF_INET6 [ T{ inet6 } ] }
+        { AF_INET [ T{ ipv4 } ] }
+        { AF_INET6 [ T{ ipv6 } ] }
         { AF_UNIX [ T{ local } ] }
         [ drop f ]
     } case ;
index 37ae1e637bffef42f663b184c402f1cee2806677..d14833e61e4dd1e3a2357a4707b9626b9a36973e 100755 (executable)
@@ -18,8 +18,8 @@ M: windows sockaddr-of-family ( alien af -- addrspec )
 \r
 M: windows addrspec-of-family ( af -- addrspec )\r
     {\r
-        { AF_INET [ T{ inet4 } ] }\r
-        { AF_INET6 [ T{ inet6 } ] }\r
+        { AF_INET [ T{ ipv4 } ] }\r
+        { AF_INET6 [ T{ ipv6 } ] }\r
         [ drop f ]\r
     } case ;\r
 \r
index 7ce7bd2016109cc8b0c6d5e78c7d78cc068e6fb2..916af4c29ae69944eb83600e7db0dce0085e497d 100644 (file)
@@ -79,3 +79,46 @@ IN: io.streams.limited.tests
     "asdf" over stream-write dup stream-flush
     3 swap stream-read
 ] unit-test
+
+[ t ]
+[
+    "abc" <string-reader> 3 limit-stream unlimit-stream
+    "abc" <string-reader> =
+] unit-test
+
+[ t ]
+[
+    "abc" <string-reader> 3 limit-stream unlimit-stream
+    "abc" <string-reader> =
+] unit-test
+
+[ t ]
+[
+    [
+        "resource:license.txt" utf8 <file-reader> &dispose
+        3 limit-stream unlimit-stream
+        "resource:license.txt" utf8 <file-reader> &dispose
+        [ decoder? ] both?
+    ] with-destructors
+] unit-test
+
+[ "asdf" ] [
+    "asdf" <string-reader> 2 <limited-stream> [
+        unlimited-input contents
+    ] with-input-stream
+] unit-test
+
+[ "asdf" ] [
+    "asdf" <string-reader> 2 <limited-stream> [
+        [ contents ] with-unlimited-input
+    ] with-input-stream
+] unit-test
+
+[ "gh" ] [
+    "asdfgh" <string-reader> 4 <limited-stream> [
+        2 [
+            [ contents drop ] with-unlimited-input
+        ] with-limited-input
+        [ contents ] with-unlimited-input
+    ] with-input-stream
+] unit-test
index 4ca1779a7b031feaff2be76740f78095f338cc5d..929520edaaf6eb49e7fdb4078a39d3471453a31d 100644 (file)
@@ -33,6 +33,10 @@ M: object limit-stream ( stream limit -- stream' )
 : with-limited-stream ( stream limit quot -- )
     [ limit-stream ] dip call ; inline
 
+: with-limited-input ( limit quot -- )
+    [ [ input-stream get ] dip limit-stream input-stream ] dip
+    with-variable ; inline
+
 ERROR: limit-exceeded n stream ;
 
 <PRIVATE
@@ -127,3 +131,20 @@ M: limited-stream dispose stream>> dispose ;
 
 M: limited-stream stream-element-type
     stream>> stream-element-type ;
+
+GENERIC: unlimit-stream ( stream -- stream' )
+
+M: decoder unlimit-stream ( stream -- stream' )
+    [ stream>> ] change-stream ;
+
+M: limited-stream unlimit-stream ( stream -- stream' ) stream>> ;
+
+: unlimited-input ( -- )
+    input-stream [ unlimit-stream ] change ;
+
+: with-unlimited-stream ( stream quot -- )
+    [ unlimit-stream ] dip call ; inline
+
+: with-unlimited-input ( quot -- )
+    [ input-stream get unlimit-stream input-stream ] dip
+    with-variable ; inline
index 8d840bc047fe6b57a896c69add80c4d340807659..fb73182f3dffc9ae026d3d604b0ab963558f22c2 100644 (file)
@@ -17,7 +17,7 @@ HELP: match-cond
 { $values { "assoc" "a sequence of pairs" } }
 { $description "Calls the second quotation in the first pair whose first sequence yields a successful " { $link match } " against the top of the stack. The second quotation, when called, has the hashtable returned from the " { $link match } " call bound as the top namespace so " { $link get } " can be used to retrieve the values. To have a fallthrough match clause use the '_' match variable." } 
 { $examples 
-    { $code "USE: match" "MATCH-VARS: ?value ;\n{ increment ?value } {\n  { { increment ?value } [ ?value do-something ] }\n  { { decrement ?value } [ ?value do-something-else ] }\n  { _ [ no-match-found ] }\n} match-cond" }
+    { $code "USE: match" "MATCH-VARS: ?value ;\n{ increment 346126 } {\n  { { increment ?value } [ ?value do-something ] }\n  { { decrement ?value } [ ?value do-something-else ] }\n  { _ [ no-match-found ] }\n} match-cond" }
 }
 { $see-also match POSTPONE: MATCH-VARS: replace-patterns match-replace } ;
 
@@ -27,7 +27,7 @@ HELP: MATCH-VARS:
 { $values { "var" "a match variable name beginning with '?'" } }
 { $description "Creates a symbol that can be used in " { $link match } " and " { $link match-cond } " for binding values in the matched sequence. The symbol name is created as a word that is defined to get the value of the symbol out of the current namespace. This can be used in " { $link match-cond } " to retrive the values in the quotation body." }
 { $examples 
-    { $code "USE: match" "MATCH-VARS: ?value ;\n{ increment ?value } {\n  { { increment ?value } [ ?value do-something ] }\n  { { decrement ?value } [ ?value do-something-else ] }\n  { _ [ no-match-found ] }\n} match-cond" }
+    { $code "USE: match" "MATCH-VARS: ?value ;\n{ increment 346126 } {\n  { { increment ?value } [ ?value do-something ] }\n  { { decrement ?value } [ ?value do-something-else ] }\n  { _ [ no-match-found ] }\n} match-cond" }
 }
 { $see-also match match-cond replace-patterns match-replace } ;
 
index 08e2ed1a9e3c45864923f0573fd761a18ab35fe4..c762d265c3e3a532dfa7574dfea2839b41f3b749 100755 (executable)
@@ -1,7 +1,7 @@
 USING: kernel math math.floats.env math.floats.env.private
 math.functions math.libm sequences tools.test locals
 compiler.units kernel.private fry compiler.test math.private
-words system ;
+words system memory ;
 IN: math.floats.env.tests
 
 : set-default-fp-env ( -- )
@@ -193,6 +193,9 @@ os openbsd eq? cpu x86.32 eq? and [
 [ +denormal-keep+ ] [ denormal-mode ] unit-test
 [ { } ] [ fp-traps ] unit-test
 
+[ ] [
+    all-fp-exceptions [ compact-gc ] with-fp-traps
+] unit-test
+
 ! In case the tests screw up the FP env because of bugs in math.floats.env
 set-default-fp-env
-
index 1d56c59fc0ee28d74ecb897abccc0973b7e0abf1..c464e5d67442401c3b26d980dd91bd011f79df44 100644 (file)
@@ -39,7 +39,7 @@ ERROR: end-of-stream multipart ;
 
 : fill-bytes ( multipart -- multipart )
     buffer-size read
-    [ '[ _ append ] change-bytes ]
+    [ '[ _ B{ } append-as ] change-bytes ]
     [ t >>end-of-stream? ] if* ;
 
 : maybe-fill-bytes ( multipart -- multipart )
@@ -151,5 +151,5 @@ ERROR: no-content-disposition multipart ;
     dup end-of-stream?>> [ process-header parse-multipart-loop ] unless ;
 
 : parse-multipart ( separator -- mime-parts )
-    <multipart> parse-beginning fill-bytes parse-multipart-loop
-    mime-parts>> ;
+    <multipart> parse-beginning fill-bytes
+    parse-multipart-loop mime-parts>> ;
index 6e9314792fa1433745905dc9d0a4fe7c95d5a79e..149168532f23d76a2fc475315935545b9755221f 100644 (file)
@@ -109,7 +109,7 @@ TUPLE: alien-callback-params < alien-node-params xt ;
 
 : callback-bottom ( params -- )
     "( callback )" <uninterned-word> >>xt
-    xt>> '[ _ callback-xt ] infer-quot-here ;
+    xt>> '[ _ callback-xt { alien } declare ] infer-quot-here ;
 
 : callback-return-quot ( ctype -- quot )
     return>> [ [ ] ] [ c-type c-type-unboxer-quot ] if-void ;
index d136f49f76bb453e0af5c9f5a9217f8c9b7065c8..47e882f2277501705ddc2dfea87da23128876aca 100644 (file)
@@ -407,6 +407,7 @@ M: object infer-call* \ call bad-macro-input ;
 \ float>bignum { float } { bignum } define-primitive \ float>bignum make-foldable
 \ float>bits { real } { integer } define-primitive \ float>bits make-foldable
 \ float>fixnum { float } { fixnum } define-primitive \ bignum>fixnum make-foldable
+\ fpu-state { } { } define-primitive
 \ fputc { object alien } { } define-primitive
 \ fread { integer alien } { object } define-primitive
 \ fseek { integer integer alien } { } define-primitive
@@ -444,6 +445,7 @@ M: object infer-call* \ call bad-macro-input ;
 \ set-alien-unsigned-8 { integer c-ptr integer } { } define-primitive
 \ set-alien-unsigned-cell { integer c-ptr integer } { } define-primitive
 \ set-context-object { object fixnum } { } define-primitive
+\ set-fpu-state { } { } define-primitive
 \ set-innermost-frame-quot { quotation callstack } { } define-primitive
 \ set-slot { object object fixnum } { } define-primitive
 \ set-special-object { object fixnum } { } define-primitive
index 8ee5ff48bd23e80e582a5d1371b8bf9444e53e53..22507b2cc35c0f28460340de23cc7c0152e3c22c 100644 (file)
@@ -8,6 +8,9 @@ HELP: disassemble
 \r
 ARTICLE: "tools.disassembler" "Disassembling words"\r
 "The " { $vocab-link "tools.disassembler" } " vocabulary provides support for disassembling compiled word definitions. It uses the " { $snippet "libudis86" } " library on x86-32 and x86-64, and " { $snippet "gdb" } " on PowerPC."\r
+$nl\r
+"See also " { $vocab-link "compiler.tree.debugger" } " and " { $vocab-link "compiler.cfg.debugger" } "."\r
+$nl\r
 { $subsections disassemble } ;\r
 \r
 ABOUT: "tools.disassembler"\r
index f821c599415753be1169bc2e34a4ec78dc235f35..8d891c1aa441771a9cb45b91e3520b6e1a574a1f 100644 (file)
@@ -10,7 +10,7 @@ ARTICLE: "timing" "Timing code and collecting statistics"
 "A lower-level word puts timings on the stack, intead of printing:"
 { $subsections benchmark }
 "You can also read the system clock directly; see " { $link "system" } "."
-{ $see-also "profiling" "calendar" } ;
+{ $see-also "profiling" "tools.annotations" "calendar" } ;
 
 ABOUT: "timing"
 
index d2fa55f7f3d4026c63193dea18dca1bfa987b700..1c9b92564128b203b15c15d9fcbdb598c36b030f 100644 (file)
@@ -1,6 +1,8 @@
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2010 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: urls urls.private io.sockets io.sockets.secure ;
 IN: urls.secure
 
+UNION: abstract-inet inet inet4 inet6 ;
+
 M: abstract-inet >secure-addr <secure> ;
old mode 100644 (file)
new mode 100755 (executable)
index 7143d03..8e3af26
@@ -340,6 +340,8 @@ tuple
     { "tag" "kernel.private" (( object -- n )) }
     { "(execute)" "kernel.private" (( word -- )) }
     { "(call)" "kernel.private" (( quot -- )) }
+    { "fpu-state" "kernel.private" (( -- )) }
+    { "set-fpu-state" "kernel.private" (( -- )) }
     { "unwind-native-frames" "kernel.private" (( -- )) }
     { "set-callstack" "kernel.private" (( callstack -- * )) }
     { "lazy-jit-compile" "kernel.private" (( -- )) }
index b307128efb2287bbd60d9a36ffa7866aac42ab9b..6285fd716a214e5306d4f21689ce2fbe2ef9a26e 100644 (file)
@@ -76,6 +76,8 @@ ERROR: no-parent-directory path ;
         [ f ]
     } cond ;
 
+PRIVATE>
+
 : absolute-path? ( path -- ? )
     {
         { [ dup empty? ] [ f ] }
@@ -85,7 +87,9 @@ ERROR: no-parent-directory path ;
         [ f ]
     } cond nip ;
 
-PRIVATE>
+: append-relative-path ( path1 path2 -- path )
+    [ trim-tail-separators ]
+    [ trim-head-separators ] bi* "/" glue ;
 
 : append-path ( path1 path2 -- path )
     {
@@ -101,10 +105,7 @@ PRIVATE>
         { [ over absolute-path? over first path-separator? and ] [
             [ 2 head ] dip append
         ] }
-        [
-            [ trim-tail-separators ]
-            [ trim-head-separators ] bi* "/" glue
-        ]
+        [ append-relative-path ]
     } cond ;
 
 : prepend-path ( path1 path2 -- path )
index f103c377b9a0e9cc585cb9d4f85778d7249e551c..4d4430d7e2f32588781b5cda8b33b0a02b163e6a 100644 (file)
@@ -1,4 +1,4 @@
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2010 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors kernel math threads io io.sockets
 io.encodings.ascii io.streams.duplex debugger tools.time
@@ -7,13 +7,14 @@ namespaces arrays continuations destructors ;
 IN: benchmark.sockets
 
 SYMBOL: counter
-SYMBOL: port-promise
+SYMBOL: server-promise
 SYMBOL: server
+SYMBOL: port
 
 CONSTANT: number-of-requests 1000
 
 : server-addr ( -- addr )
-    "127.0.0.1" port-promise get ?promise <inet4> ;
+    "127.0.0.1" port get <inet4> ;
 
 : server-loop ( server -- )
     dup accept drop [
@@ -28,13 +29,8 @@ CONSTANT: number-of-requests 1000
     ] curry "Client handler" spawn drop server-loop ;
 
 : simple-server ( -- )
-    [
-        "127.0.0.1" 0 <inet4> ascii <server>
-        [ server set ]
-        [ addr>> port>> port-promise get fulfill ]
-        [ [ server-loop ] with-disposal ]
-        tri
-    ] ignore-errors ;
+    [ server get [ server-loop ] with-disposal ] ignore-errors
+    t server-promise get fulfill ;
 
 : simple-client ( -- )
     [
@@ -53,14 +49,17 @@ CONSTANT: number-of-requests 1000
 
 : clients ( n -- )
     dup pprint " clients: " write [
-        <promise> port-promise set
+        <promise> server-promise set
         dup <count-down> counter set
+        "127.0.0.1" 0 <inet4> ascii <server>
+        [ server set ] [ addr>> port>> port set ] bi
+
         [ simple-server ] "Simple server" spawn drop
-        yield yield
         [ [ simple-client ] "Simple client" spawn drop ] times
+
         counter get await
         stop-server
-        yield yield
+        server-promise get ?promise drop
     ] benchmark . flush ;
 
 : socket-benchmarks ( -- )
index 9dedb6410b051b6b0e7f246c7f08bf53bb24274a..e9e0902e4809c0cb81eeb1270721ab329ce70834 100644 (file)
@@ -9,7 +9,7 @@ IN: geo-ip
 
 : db-path ( -- path ) "IpToCountry.csv" temp-file ;
 
-CONSTANT: db-url "http://software77.net/cgi-bin/ip-country/geo-ip.pl?action=download"
+CONSTANT: db-url "http://software77.net/geo-ip/?DL=1"
 
 : download-db ( -- path )
     db-path dup exists? [
index 02337276e61e9ab0d013d49f451d3474ffc2d8da..c6fc67a8c63164e8026369020075e2b49ad3f372 100644 (file)
@@ -2,7 +2,7 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: fry irc.client irc.client.chats kernel namespaces
 sequences threads io.launcher io splitting
-make mason.common mason.updates calendar math timers
+make mason.common mason.git calendar math timers
 io.encodings.8-bit.latin1 debugger ;
 IN: irc.gitbot
 
@@ -47,7 +47,9 @@ M: object handle-message drop ;
 
 : check-for-updates ( chat -- )
     '[
-        git-id git-pull-cmd short-running-process git-id
+        git-id
+        { "git" "pull" "origin" "master" } short-running-process
+        git-id
         _ report-updates
     ] try ;
 
index f2018449fc4dc4cd0bcfec79d3271b5a2f408d56..e037bdba0cb8c35bf987f7a889f0f48fdf8ea3d8 100644 (file)
@@ -1,9 +1,10 @@
-! Copyright (C) 2008, 2009 Eduardo Cavazos, Slava Pestov.
+! Copyright (C) 2008, 2010 Eduardo Cavazos, Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: arrays kernel calendar io.directories io.encodings.utf8
-io.files io.launcher namespaces prettyprint combinators mason.child
-mason.cleanup mason.common mason.help mason.release mason.report
-mason.email mason.notify ;
+io.files io.launcher io.pathnames namespaces prettyprint
+combinators mason.child mason.cleanup mason.common mason.config
+mason.docs mason.release mason.report mason.email mason.git
+mason.notify mason.platform mason.updates ;
 QUALIFIED: continuations
 IN: mason.build
 
@@ -11,12 +12,18 @@ IN: mason.build
     now datestamp stamp set
     build-dir make-directory ;
 
-: enter-build-dir  ( -- ) build-dir set-current-directory ;
+: enter-build-dir  ( -- )
+    build-dir set-current-directory ;
 
-: clone-builds-factor ( -- )
-    "git" "clone" builds/factor 3array short-running-process ;
+: clone-source ( -- )
+    "git" "clone" builds-dir get "factor" append-path 3array
+    short-running-process ;
 
-: begin-build ( -- )
+: copy-image ( -- )
+    builds-dir get boot-image-name append-path
+    [ "." copy-file-into ] [ "factor" copy-file-into ] bi ;
+
+: save-git-id ( -- )
     "factor" [ git-id ] with-directory {
         [ "git-id" to-file ]
         [ "factor/git-id" to-file ]
@@ -24,15 +31,20 @@ IN: mason.build
         [ notify-begin-build ]
     } cleave ;
 
+: begin-build ( -- )
+    clone-source
+    copy-image
+    save-git-id ;
+
 : build ( -- )
     create-build-dir
     enter-build-dir
-    clone-builds-factor
     [
         begin-build
         build-child
         [ notify-report ]
-        [ status-clean eq? [ upload-help release ] when ] bi
+        [ status-clean eq? [ upload-docs release ] when ] bi
+        finish-build
     ] [ cleanup ] [ ] continuations:cleanup ;
 
 MAIN: build
index d9821f8fcc82a7efdd12fd33413dbc27a5187542..66e6eb3722da0d6c9632e762b9bcf551f0a06dc5 100644 (file)
@@ -29,13 +29,6 @@ IN: mason.child
         try-process
     ] with-directory ;
 
-: builds-factor-image ( -- img )
-    builds/factor boot-image-name append-path ;
-
-: copy-image ( -- )
-    builds-factor-image "." copy-file-into
-    builds-factor-image "factor" copy-file-into ;
-
 : factor-vm ( -- string )
     target-os get "winnt" = "./factor.com" "./factor" ? ;
 
@@ -81,7 +74,6 @@ MACRO: recover-cond ( alist -- )
     ] if ;
 
 : build-child ( -- status )
-    copy-image
     {
         { [ notify-make-vm make-vm ] [ compile-failed ] }
         { [ notify-boot boot ] [ boot-failed ] }
index b8e01d39937097de7ef85d869e98dc0b1801dd22..1d1ea3d89162a865413ecfabfd110c1e51b6500a 100644 (file)
@@ -5,13 +5,6 @@ io.files.temp io.encodings.utf8 sequences ;
 
 [ "00:01:02" ] [ 62,000,000,000 nanos>time ] unit-test
 
-[ "/home/bobby/builds/factor" ] [
-    [
-        "/home/bobby/builds" builds-dir set
-        builds/factor
-    ] with-scope
-] unit-test
-
 [ t ] [
     [
         "/home/bobby/builds" builds-dir set
index db68a558e094e68031866cb76e5a4532fd445e66..08b979e744b93e082e984723b14578585490428a 100644 (file)
@@ -1,4 +1,4 @@
-! Copyright (C) 2008, 2009 Eduardo Cavazos, Slava Pestov.
+! Copyright (C) 2008, 2010 Eduardo Cavazos, Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel namespaces sequences splitting system accessors
 math.functions make io io.files io.pathnames io.directories
@@ -20,16 +20,19 @@ SYMBOL: current-git-id
     #! 30 minutes to complete, to catch hangs.
     >process 30 minutes >>timeout try-output-process ;
 
-HOOK: really-delete-tree os ( path -- )
+HOOK: (really-delete-tree) os ( path -- )
 
-M: windows really-delete-tree
+M: windows (really-delete-tree)
     #! Workaround: Cygwin GIT creates read-only files for
     #! some reason.
     [ { "chmod" "ug+rw" "-R" } swap absolute-path suffix short-running-process ]
     [ delete-tree ]
     bi ;
 
-M: unix really-delete-tree delete-tree ;
+M: unix (really-delete-tree) delete-tree ;
+
+: really-delete-tree ( path -- )
+    dup exists? [ (really-delete-tree) ] [ drop ] if ;
 
 : retry ( n quot -- )
     [ iota ] dip
@@ -65,22 +68,8 @@ M: unix really-delete-tree delete-tree ;
 
 SYMBOL: stamp
 
-: builds/factor ( -- path ) builds-dir get "factor" append-path ;
 : build-dir ( -- path ) builds-dir get stamp get append-path ;
 
-: prepare-build-machine ( -- )
-    builds-dir get make-directories
-    builds-dir get
-    [ { "git" "clone" "git://factorcode.org/git/factor.git" } try-output-process ]
-    with-directory ;
-
-: git-id ( -- id )
-    { "git" "show" } utf8 [ lines ] with-process-reader
-    first " " split second ;
-
-: ?prepare-build-machine ( -- )
-    builds/factor exists? [ prepare-build-machine ] unless ;
-
 CONSTANT: load-all-vocabs-file "load-everything-vocabs"
 CONSTANT: load-all-errors-file "load-everything-errors"
 
index b72b949ed5a25af9b37d0b452f6edc4556484002..1d433864569cef9f777708c57d4f0adc3605cefd 100644 (file)
@@ -34,24 +34,36 @@ target-os get-global [
 ! Keep test-log around?
 SYMBOL: builder-debug
 
+! URL for counter notifications.
+SYMBOL: counter-url
+
+counter-url [ "http://builds.factorcode.org/counter" ] initialize
+
 ! URL for status notifications.
 SYMBOL: status-url
 
+status-url [ "http://builds.factorcode.org/status-update" ] initialize
+
 ! Password for status notifications.
 SYMBOL: status-secret
 
-SYMBOL: upload-help?
+SYMBOL: upload-docs?
 
-! The below are only needed if upload-help is true.
+! The below are only needed if upload-docs? is true.
 
-! Host with HTML help
-SYMBOL: help-host
+! Host to upload docs to
+SYMBOL: docs-host
 
 ! Username to log in.
-SYMBOL: help-username
+SYMBOL: docs-username
 
 ! Directory to upload docs to.
-SYMBOL: help-directory
+SYMBOL: docs-directory
+
+! URL to notify server about new docs
+SYMBOL: docs-update-url
+
+docs-update-url [ "http://builds.factorcode.org/docs-update" ] initialize
 
 ! Boolean. Do we release binaries and update the clean branch?
 SYMBOL: upload-to-factorcode?
diff --git a/extra/mason/disk/authors.txt b/extra/mason/disk/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/extra/mason/disk/disk-tests.factor b/extra/mason/disk/disk-tests.factor
new file mode 100644 (file)
index 0000000..b1c0a7e
--- /dev/null
@@ -0,0 +1,6 @@
+USING: mason.disk tools.test strings sequences ;
+IN: mason.disk.tests
+
+[ t ] [ disk-usage string? ] unit-test
+
+[ t ] [ sufficient-disk-space? { t f } member? ] unit-test
diff --git a/extra/mason/disk/disk.factor b/extra/mason/disk/disk.factor
new file mode 100644 (file)
index 0000000..ca4a703
--- /dev/null
@@ -0,0 +1,27 @@
+! Copyright (C) 2010 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors io.files.info io.pathnames kernel math
+math.parser namespaces sequences mason.config ;
+IN: mason.disk
+
+: gb ( -- n ) 30 2^ ; inline
+
+: sufficient-disk-space? ( -- ? )
+    ! We want at least 300Mb to be available before starting
+    ! a build.
+    current-directory get file-system-info available-space>>
+    gb > ;
+
+: check-disk-space ( -- )
+    sufficient-disk-space? [
+        "Less than 1 Gb free disk space." throw
+    ] unless ;
+
+: mb-str ( n -- string ) gb /i number>string ;
+
+: disk-usage ( -- string )
+    builds-dir get file-system-info
+    [ used-space>> ] [ total-space>> ] bi
+    [ [ mb-str ] bi@ " / " glue " Gb used" append ]
+    [ [ 100 * ] dip /i number>string "(" "%)" surround ] 2bi
+    " " glue ;
diff --git a/extra/mason/docs/docs.factor b/extra/mason/docs/docs.factor
new file mode 100644 (file)
index 0000000..0c3feaa
--- /dev/null
@@ -0,0 +1,31 @@
+! Copyright (C) 2008, 2010 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays hashtables help.html http.client io.directories
+io.files io.launcher kernel make mason.common mason.config
+namespaces sequences ;
+IN: mason.docs
+
+: make-docs-archive ( -- )
+    "factor/temp" [
+        { "tar" "cfz" "docs.tar.gz" "docs" } short-running-process
+    ] with-directory ;
+
+: upload-docs-archive ( -- )
+    "factor/temp/docs.tar.gz"
+    docs-username get
+    docs-host get
+    docs-directory get "/docs.tar.gz" append
+    upload-safely ;
+
+: notify-docs ( -- )
+    status-secret get "secret" associate
+    docs-update-url get
+    http-post
+    2drop ;
+
+: upload-docs ( -- )
+    upload-docs? get [
+        make-docs-archive
+        upload-docs-archive
+        notify-docs
+    ] when ;
\ No newline at end of file
index 1389a2e27c4dac4d4e5b232ba18add0c95e18057..68724b3ffa2be6ef40c342c3320a73d0dd8133f1 100644 (file)
@@ -1,18 +1,24 @@
 ! Copyright (C) 2008, 2010 Eduardo Cavazos, Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: kernel namespaces accessors combinators make smtp debugger
-prettyprint sequences io io.streams.string io.encodings.utf8 io.files
-io.sockets mason.common mason.platform mason.config ;
+USING: accessors calendar combinators continuations debugger fry
+io io.encodings.utf8 io.files io.sockets kernel make
+mason.common mason.config mason.platform math.order namespaces
+prettyprint sequences smtp ;
 IN: mason.email
 
 : mason-email ( body content-type subject -- )
-    <email>
-        builder-from get >>from
-        builder-recipients get >>to
-        swap >>subject
-        swap >>content-type
-        swap >>body
-    send-email ;
+    '[
+        <email>
+            builder-from get >>from
+            builder-recipients get >>to
+            _ >>body
+            _ >>content-type
+            _ >>subject
+        send-email
+    ] [
+        "E-MAILING FAILED:" print
+        error. flush
+    ] recover ;
 
 : subject-prefix ( -- string )
     "mason on " platform ": " 3append ;
@@ -32,11 +38,52 @@ IN: mason.email
 : email-report ( report status -- )
     [ "text/html" ] dip report-subject mason-email ;
 
-: email-error ( error callstack -- )
+! Some special logic to throttle the amount of fatal errors
+! coming in, if eg git-daemon goes down on factorcode.org and
+! it fails pulling every 5 minutes.
+
+SYMBOL: last-email-time
+
+SYMBOL: next-email-time
+
+: send-email-throttled? ( -- ? )
+    ! We sent too many errors. See if its time to send a new
+    ! one again.
+    now next-email-time get-global after?
+    [ f next-email-time set-global t ] [ f ] if ;
+
+: throttle-time ( -- dt ) 6 hours ;
+
+: throttle-emails ( -- )
+    ! Last e-mail was less than 20 minutes ago. Don't send any
+    ! errors for 4 hours.
+    throttle-time hence next-email-time set-global
+    f last-email-time set-global ;
+
+: maximum-frequency ( -- dt ) 30 minutes ;
+
+: send-email-capped? ( -- ? )
+    ! We're about to send an error after sending another one.
+    ! See if we should start throttling emails.
+    last-email-time get-global
+    maximum-frequency ago
+    after?
+    [ throttle-emails f ] [ t ] if ;
+
+: email-fatal? ( -- ? )
+    {
+        { [ next-email-time get-global ] [ send-email-throttled? ] }
+        { [ last-email-time get-global ] [ send-email-capped? ] }
+        [ now last-email-time set-global t ]
+    } cond
+    dup [ now last-email-time set-global ] when ;
+
+: email-fatal ( string subject -- )
+    [ print nl print flush ]
     [
-        "Fatal error on " write host-name print nl
-        [ error. ] [ callstack. ] bi*
-    ] with-string-writer
-    "text/plain"
-    subject-prefix "fatal error" append
-    mason-email ;
+        email-fatal? [
+            now last-email-time set-global
+            [ "text/plain" subject-prefix ] dip append
+            mason-email
+        ] [ 2drop ] if
+    ] 2bi ;
diff --git a/extra/mason/git/authors.txt b/extra/mason/git/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/extra/mason/git/git.factor b/extra/mason/git/git.factor
new file mode 100644 (file)
index 0000000..df344be
--- /dev/null
@@ -0,0 +1,102 @@
+! Copyright (C) 2010 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators.short-circuit continuations
+debugger io io.directories io.encodings.utf8 io.files
+io.launcher io.sockets io.streams.string kernel mason.common
+mason.email sequences splitting ;
+IN: mason.git
+
+: git-id ( -- id )
+    { "git" "show" } utf8 [ lines ] with-process-reader
+    first " " split second ;
+
+<PRIVATE
+
+: git-clone-cmd ( -- cmd )
+    {
+        "git"
+        "clone"
+        "git://factorcode.org/git/factor.git"
+    } ;
+
+: git-clone ( -- )
+    #! Must be run from builds-dir
+    git-clone-cmd try-output-process ;
+
+: git-pull-cmd ( -- cmd )
+    {
+        "git"
+        "pull"
+        "git://factorcode.org/git/factor.git"
+        "master"
+    } ;
+
+: repo-corrupted-body ( error -- string )
+    [
+        "Corrupted repository on " write host-name write " will be re-cloned." print
+        "Error while pulling was:" print
+        nl
+        error.
+    ] with-string-writer ;
+
+: git-repo-corrupted ( error -- )
+    repo-corrupted-body "corrupted repo" email-fatal
+    "factor" really-delete-tree
+    git-clone ;
+
+: git-pull-failed ( error -- )
+    dup output-process-error? [
+        dup output>> "not uptodate. Cannot merge." swap start
+        [ git-repo-corrupted ]
+        [ rethrow ]
+        if
+    ] [ rethrow ] if ;
+
+: with-process-reader* ( desc encoding quot -- )
+    [ <process-reader*> ] dip swap [ with-input-stream ] dip
+    dup wait-for-process dup { 0 1 } member?
+    [ 2drop ] [ process-failed ] if ; inline
+
+: git-status-cmd ( -- cmd )
+    { "git" "status" } ;
+
+: git-status-failed ( error -- )
+    #! Exit code 1 means there's nothing to commit.
+    dup { [ process-failed? ] [ code>> 1 = ] } 1&&
+    [ drop ] [ rethrow ] if ;
+
+: git-status ( -- seq )
+    [
+        git-status-cmd utf8 [ lines ] with-process-reader*
+        [ "#\t" head? ] filter
+    ] [ git-status-failed { } ] recover ;
+
+: check-repository ( -- seq )
+    "factor" [ git-status ] with-directory ;
+
+: repo-dirty-body ( error -- string )
+    [
+        "Dirty repository on " write host-name write " will be re-cloned." print
+        "Modified and untracked files:" print nl
+        [ print ] each
+    ] with-string-writer ;
+
+: git-repo-dirty ( files -- )
+    repo-dirty-body "dirty repo" email-fatal
+    "factor" really-delete-tree
+    git-clone ;
+
+PRIVATE>
+
+: git-pull ( -- id )
+    #! Must be run from builds-dir.
+    "factor" exists? [
+        check-repository [
+            "factor" [
+                [ git-pull-cmd short-running-process ]
+                [ git-pull-failed ]
+                recover
+            ] with-directory
+        ] [ git-repo-dirty ] if-empty
+    ] [ git-clone ] if
+    "factor" [ git-id ] with-directory ;
diff --git a/extra/mason/help/help.factor b/extra/mason/help/help.factor
deleted file mode 100644 (file)
index 6b44e49..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-! Copyright (C) 2008, 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: arrays help.html io.directories io.files io.launcher
-kernel make mason.common mason.config namespaces sequences ;
-IN: mason.help
-
-: make-help-archive ( -- )
-    "factor/temp" [
-        { "tar" "cfz" "docs.tar.gz" "docs" } short-running-process
-    ] with-directory ;
-
-: upload-help-archive ( -- )
-    "factor/temp/docs.tar.gz"
-    help-username get
-    help-host get
-    help-directory get "/docs.tar.gz" append
-    upload-safely ;
-
-: upload-help ( -- )
-    upload-help? get [
-        make-help-archive
-        upload-help-archive
-    ] when ;
\ No newline at end of file
index 3afa56290b5a7a9a2f3e0c4434470f579fdf5a3d..7d20ee0d4d12ec7d0aa4c83835235cdc72af6b30 100755 (executable)
@@ -1,33 +1,38 @@
 ! Copyright (C) 2008, 2010 Eduardo Cavazos, Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors calendar continuations debugger io
-io.directories io.files kernel mason.common
-mason.email mason.updates mason.notify namespaces threads ;
+io.directories io.pathnames io.sockets io.streams.string kernel
+mason.config mason.disk mason.email mason.notify mason.updates
+namespaces prettyprint threads ;
 FROM: mason.build => build ;
 IN: mason
 
-: build-loop-error ( error -- )
-    [ "Build loop error:" print flush error. flush :c flush ]
-    [ error-continuation get call>> email-error ] bi ;
+: fatal-error-body ( error callstack -- string )
+    [
+        "Fatal error on " write host-name print nl
+        [ error. ] [ callstack. ] bi*
+    ] with-string-writer ;
 
-: build-loop-fatal ( error -- )
-    "FATAL BUILDER ERROR:" print
-    error. flush ;
+: build-loop-error ( error callstack -- )
+    fatal-error-body
+     "build loop error"
+     email-fatal ;
 
 : build-loop ( -- )
-    ?prepare-build-machine
+    notify-heartbeat
+
     [
-        notify-heartbeat
-        [
-            builds/factor set-current-directory
-            new-code-available? [ build ] when
-        ] [
-            build-loop-error
-        ] recover
+        builds-dir get make-directories
+        builds-dir get [
+            check-disk-space
+            update-sources
+            build? [ build ] [ 5 minutes sleep ] if
+        ] with-directory
     ] [
-        build-loop-fatal
+        error-continuation get call>> build-loop-error
+        5 minutes sleep
     ] recover
-    5 minutes sleep
+
     build-loop ;
 
 MAIN: build-loop
\ No newline at end of file
index 144f0de122dd82766a1d5270c81652dab11badfa..b5580fe162127d763f7a16736d8ae812296ba5fb 100644 (file)
@@ -2,20 +2,27 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors fry http.client io io.encodings.utf8 io.files
 kernel mason.common mason.config mason.email mason.twitter
-namespaces prettyprint sequences ;
+namespaces prettyprint sequences debugger continuations ;
 IN: mason.notify
 
 : status-notify ( report arg message -- )
-    [
-        short-host-name "host-name" set
-        target-cpu get "target-cpu" set
-        target-os get "target-os" set
-        status-secret get "secret" set
-        "message" set
-        "arg" set
-        "report" set
-    ] H{ } make-assoc
-    [ 5 ] dip '[ _ status-url get http-post 2drop ] retry ;
+    '[
+        5 [
+            [
+                short-host-name "host-name" set
+                target-cpu get "target-cpu" set
+                target-os get "target-os" set
+                status-secret get "secret" set
+                _ "report" set
+                _ "arg" set
+                _ "message" set
+            ] H{ } make-assoc
+            status-url get http-post 2drop
+        ] retry
+    ] [
+        "STATUS NOTIFY FAILED:" print
+        error. flush
+    ] recover ;
 
 : notify-heartbeat ( -- )
     f f "heartbeat" status-notify ;
index c5567c9c970fb287b319b2f32386096f14c47034..926207be0033940e90845e97bab4312b8de040eb 100644 (file)
@@ -1,10 +1,10 @@
-! Copyright (C) 2008, 2009 Eduardo Cavazos, Slava Pestov.
+! Copyright (C) 2008, 2010 Eduardo Cavazos, Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: benchmark combinators.smart debugger fry io assocs
 io.encodings.utf8 io.files io.sockets io.streams.string kernel
-locals mason.common mason.config mason.platform math namespaces
-prettyprint sequences xml.syntax xml.writer combinators.short-circuit
-literals splitting ;
+locals mason.common mason.config mason.disk mason.platform math
+namespaces prettyprint sequences xml.syntax xml.writer
+combinators.short-circuit literals splitting ;
 IN: mason.report
 
 : git-link ( id -- link )
@@ -15,12 +15,14 @@ IN: mason.report
     target-os get
     target-cpu get
     short-host-name
+    disk-usage
     build-dir
     current-git-id get git-link
     [XML
     <h1>Build report for <->/<-></h1>
     <table>
     <tr><td>Build machine:</td><td><-></td></tr>
+    <tr><td>Disk usage:</td><td><-></td></tr>
     <tr><td>Build directory:</td><td><-></td></tr>
     <tr><td>GIT ID:</td><td><-></td></tr>
     </table>
diff --git a/extra/mason/server/server-tests.factor b/extra/mason/server/server-tests.factor
new file mode 100644 (file)
index 0000000..f7cac5f
--- /dev/null
@@ -0,0 +1,15 @@
+USING: continuations db db.sqlite io.directories io.files.temp
+mason.server tools.test ;
+IN: mason.server.tests
+
+[ "test.db" temp-file delete-file ] ignore-errors
+
+[ 0 1 2 ] [
+    "test.db" temp-file <sqlite-db> [
+        init-mason-db
+
+        counter-value
+        increment-counter-value
+        increment-counter-value
+    ] with-db
+] unit-test
index d0fe29b91798b4a65461b0a853477f5f9d0d4384..1b00c165761d782136b6ecf37bbac48eadcf1f44 100644 (file)
@@ -1,6 +1,7 @@
 ! Copyright (C) 2010 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: db db.sqlite db.tuples db.types kernel ;
+USING: accessors calendar db db.sqlite db.tuples db.types kernel
+math math.order sequences combinators.short-circuit ;
 IN: mason.server
 
 CONSTANT: +starting+ "starting"
@@ -23,13 +24,13 @@ builder "BUILDERS" {
     { "host-name" "HOST_NAME" TEXT +user-assigned-id+ }
     { "os" "OS" TEXT +user-assigned-id+ }
     { "cpu" "CPU" TEXT +user-assigned-id+ }
-    
+
     { "clean-git-id" "CLEAN_GIT_ID" TEXT }
     { "clean-timestamp" "CLEAN_TIMESTAMP" TIMESTAMP }
 
     { "last-release" "LAST_RELEASE" TEXT }
     { "release-git-id" "RELEASE_GIT_ID" TEXT }
-    
+
     { "last-git-id" "LAST_GIT_ID" TEXT }
     { "last-timestamp" "LAST_TIMESTAMP" TIMESTAMP }
     { "last-report" "LAST_REPORT" TEXT }
@@ -40,7 +41,47 @@ builder "BUILDERS" {
     { "status" "STATUS" TEXT }
 } define-persistent
 
+TUPLE: counter id value ;
+
+counter "COUNTER" {
+    { "id" "ID" INTEGER +db-assigned-id+ }
+    { "value" "VALUE" INTEGER }
+} define-persistent
+
+: counter-tuple ( -- counter )
+    counter new select-tuple
+    [ counter new dup insert-tuple ] unless* ;
+
+: counter-value ( -- n )
+    [ counter-tuple value>> 0 or ] with-transaction ;
+
+: increment-counter-value ( -- n )
+    [
+        counter-tuple [ 0 or 1 + dup ] change-value update-tuple
+    ] with-transaction ;
+
+: crashed-builders ( -- seq )
+    builder new select-tuples
+    [ current-timestamp>> 5 hours ago before? ] filter ;
+
+: broken-builders ( -- seq )
+    builder new select-tuples
+    [
+        clean-timestamp>>
+        { [ not ] [ 1 weeks ago before? ] } 1||
+    ] filter ;
+
+: funny-builders ( -- crashed broken limbo )
+    builder new select-tuples
+    [ [ current-timestamp>> 5 hours ago before? ] filter ]
+    [ [ clean-timestamp>> 1 weeks ago before? ] filter ]
+    [ [ [ clean-git-id>> ] [ release-git-id>> ] bi = not ] filter ]
+    tri ;
+
 : mason-db ( -- db ) "resource:mason.db" <sqlite-db> ;
 
 : with-mason-db ( quot -- )
     [ mason-db ] dip with-db ; inline
+
+: init-mason-db ( -- )
+    { builder counter } ensure-tables ;
index 4221bd4376e20e8727ba360928ca7eecf896ef4b..016c1a6d7974da4fa87aa844d0f308e2c5be7271 100644 (file)
@@ -1,26 +1,38 @@
 ! Copyright (C) 2008, 2010 Eduardo Cavazos, Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: bootstrap.image.download io.directories io.launcher
-kernel mason.common mason.platform ;
+USING: bootstrap.image.download http.client init kernel
+math.parser namespaces mason.config mason.common mason.git
+mason.platform ;
 IN: mason.updates
 
-: git-pull-cmd ( -- cmd )
-    {
-        "git"
-        "pull"
-        "--no-summary"
-        "git://factorcode.org/git/factor.git"
-        "master"
-    } ;
-
-: updates-available? ( -- ? )
-    git-id
-    git-pull-cmd short-running-process
-    git-id
-    = not ;
-
-: new-image-available? ( -- ? )
-    boot-image-name maybe-download-image ;
-
-: new-code-available? ( -- ? )
-    updates-available? new-image-available? or ;
+TUPLE: sources git-id boot-image counter ;
+
+C: <sources> sources
+
+SYMBOLS: latest-sources last-built-sources ;
+
+[
+    f latest-sources set-global
+    f last-built-sources set-global
+] "mason.updates" add-startup-hook
+
+: latest-boot-image ( -- boot-image )
+    boot-image-name
+    [ maybe-download-image drop ] [ file-checksum ] bi ;
+
+: latest-counter ( -- counter )
+    counter-url get-global http-get nip string>number ;
+
+: update-sources ( -- )
+    #! Must be run from builds-dir
+    git-pull latest-boot-image latest-counter <sources>
+    latest-sources set-global ;
+
+: build? ( -- ? )
+    latest-sources get-global last-built-sources get-global = not ;
+
+: finish-build ( -- )
+    #! If the build completed (successfully or not) without
+    #! mason crashing or being killed, don't build this git ID
+    #! and boot image hash again.
+    latest-sources get-global last-built-sources set-global ;
index 8ff131d5a2f540eb2f69ad96716cfa9c0afb52b5..9236cc9504db965ed715f64362ac143631e00632 100644 (file)
@@ -2,7 +2,7 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors assocs combinators hashtables http
 http.client json.reader kernel macros namespaces sequences
-urls.secure fry oauth urls ;
+urls.secure fry oauth urls system ;
 IN: twitter
 
 ! Configuration
@@ -19,22 +19,27 @@ twitter-source [ "factor" ] initialize
         call
     ] with-scope ; inline
 
+: twitter-url ( string -- string' )
+    os windows?
+    "http://twitter.com/"
+    "https://twitter.com/" ? prepend ;
+
 PRIVATE>
 
 : obtain-twitter-request-token ( -- request-token )
     [
-        "https://twitter.com/oauth/request_token"
+        "oauth/request_token" twitter-url
         <request-token-params>
         obtain-request-token
     ] with-twitter-oauth ;
 
 : twitter-authorize-url ( token -- url )
-    "https://twitter.com/oauth/authorize" >url
+    "oauth/authorize" twitter-url >url
         swap key>> "oauth_token" set-query-param ;
 
 : obtain-twitter-access-token ( request-token verifier -- access-token )
     [
-        [ "https://twitter.com/oauth/access_token" ] 2dip
+        [ "oauth/access_token" twitter-url ] 2dip
         <access-token-params>
             swap >>verifier
             swap >>request-token
@@ -48,8 +53,8 @@ MACRO: keys-boa ( keys class -- )
     [ [ '[ _ swap at ] ] map ] dip '[ _ cleave _ boa ] ;
 
 ! Twitter requests
-: twitter-url ( string -- url )
-    "https://twitter.com/statuses/" ".json" surround ;
+: status-url ( string -- url )
+    "statuses/" ".json" surround twitter-url ;
 
 : set-request-twitter-auth ( request -- request )
     [ <oauth-request-params> set-oauth ] with-twitter-oauth ;
@@ -131,7 +136,7 @@ PRIVATE>
     ] H{ } make-assoc ;
 
 : (tweet) ( string -- json )
-    update-post-data "update" twitter-url
+    update-post-data "update" status-url
     <post-request> twitter-request ;
 
 PRIVATE>
@@ -145,7 +150,7 @@ PRIVATE>
 <PRIVATE
 
 : timeline ( url -- tweets )
-    twitter-url <get-request>
+    status-url <get-request>
     twitter-request json>twitter-statuses ;
 
 PRIVATE>
diff --git a/extra/webapps/mason/counter/counter.factor b/extra/webapps/mason/counter/counter.factor
new file mode 100644 (file)
index 0000000..8e2de23
--- /dev/null
@@ -0,0 +1,14 @@
+! Copyright (C) 2010 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors furnace.actions http.server.responses
+mason.server math.parser ;
+IN: webapps.mason.counter
+
+: <counter-action> ( -- action )
+    <action>
+    [
+        [
+            counter-value number>string
+            "text/plain" <content>
+        ] with-mason-db
+    ] >>display ;
diff --git a/extra/webapps/mason/dashboard.xml b/extra/webapps/mason/dashboard.xml
new file mode 100644 (file)
index 0000000..547e344
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version='1.0' ?>
+
+<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
+       <t:title>Mason dashboard</t:title>
+
+       <h1>Crashed build machines</h1>
+       <p>Machines which have not sent a heartbeat for several hours:</p>
+       <t:xml t:name="crashed" />
+
+       <h1>Broken build machines</h1>
+       <p>Machines which have not had a successful build for over a week:</p>
+       <t:xml t:name="broken" />
+
+       <h1>Build machines in limbo</h1>
+       <p>Machines with a clean build that have not uploaded binary for that build:</p>
+       <t:xml t:name="limbo" />
+
+       <h1>Force build now</h1>
+       <p>Requires build engineer status.</p>
+
+       <t:form t:action="$mason-app/dashboard/increment-counter">
+               <p><button type="submit">Increment counter</button></p>
+       </t:form>
+
+       <h1>Make a release</h1>
+       <p>Requires build engineer status.</p>
+
+       <t:form t:action="$mason-app/dashboard/make-release">
+               <table>
+                       <tr><td>Version:</td><td><t:field t:name="version" /></td></tr>
+                       <tr><td>Announcement URL:</td><td><t:field t:name="announcement-url" /></td></tr>
+               </table>
+
+               <p><button type="submit">Go</button></p>
+       </t:form>
+</t:chloe>
diff --git a/extra/webapps/mason/dashboard/dashboard.factor b/extra/webapps/mason/dashboard/dashboard.factor
new file mode 100644 (file)
index 0000000..2bd9287
--- /dev/null
@@ -0,0 +1,26 @@
+! Copyright (C) 2010 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel mason.server furnace.actions
+html.forms sequences xml.syntax webapps.mason.utils ;
+IN: webapps.mason.downloads
+
+: builder-list ( seq -- xml )
+    [
+        [ package-url ] [ [ os>> ] [ cpu>> ] bi "/" glue ] bi
+        [XML <li><a href=<->><-></a></li> XML]
+    ] map
+    [ [XML <p>No machines.</p> XML] ]
+    [ [XML <ul><-></ul> XML] ]
+    if-empty ;
+
+: <dashboard-action> ( -- action )
+    <page-action>
+    [
+        [
+            funny-builders
+            [ builder-list ] tri@
+            [ "crashed" set-value ]
+            [ "broken" set-value ]
+            [ "limbo" set-value ] tri*
+        ] with-mason-db
+    ] >>init ;
diff --git a/extra/webapps/mason/docs-update/authors.txt b/extra/webapps/mason/docs-update/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/extra/webapps/mason/docs-update/docs-update.factor b/extra/webapps/mason/docs-update/docs-update.factor
new file mode 100644 (file)
index 0000000..7b68589
--- /dev/null
@@ -0,0 +1,29 @@
+! Copyright (C) 2010 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors continuations furnace.actions help.html
+http.server.responses io.directories io.directories.hierarchy
+io.launcher io.files io.pathnames kernel memoize threads
+webapps.mason.utils ;
+IN: webapps.mason.docs-update
+
+: update-docs ( -- )
+    home [
+        "newdocs" make-directory
+        "newdocs" [ { "tar" "xfz" "../docs.tar.gz" } try-process ] with-directory
+
+        "docs" exists? [ "docs" "docs.old" move-file ] when
+        "newdocs/docs" "docs" move-file
+
+        "newdocs" delete-directory
+        "docs.old" exists? [ "docs.old" delete-tree ] when
+
+        \ load-index reset-memoized
+    ] with-directory ;
+
+: <docs-update-action> ( -- action )
+    <action>
+    [ validate-secret ] >>validate
+    [
+        [ update-docs ] "Documentation update" spawn drop
+        "OK" "text/plain" <content>
+    ] >>submit ;
index d2cfab65909c448853195e1891db681796e5a5f2..9d18b6ed7c78941b35b16b14f0ae0ed72ad4d0e8 100644 (file)
@@ -5,39 +5,33 @@
 
 <t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
 
-<html xmlns="http://www.w3.org/1999/xhtml">
-  <head>
-    <link rel="stylesheet" href="http://factorcode.org/css/master.css" type="text/css" media="screen" title="no title" charset="utf-8" />
-    <title>Factor binary package for <t:label t:name="platform" /></title>
-  </head>
-  <body>
-    <div><img src="http://factorcode.org/graphics/logo.png" alt="Logo" /></div>
+       <t:title>Factor binary package for <t:label t:name="platform" /></t:title>
 
-    <h1>Factor binary package for <t:label t:name="platform" /></h1>
+       <div><img src="http://factorcode.org/graphics/logo.png" alt="Logo" /></div>
 
-    <p>Requirements:</p>
-    <t:xml t:name="requirements" />
+       <h1>Factor binary package for <t:label t:name="platform" /></h1>
 
-    <h2>Download <t:xml t:name="package" /></h2>
+       <p>Requirements:</p>
+       <t:xml t:name="requirements" />
 
-    <p>This package was built from GIT ID <t:xml t:name="git-id" />.</p>
+       <h2>Download <t:xml t:name="package" /></h2>
 
-    <p>Once you download Factor, you can <a href="http://concatenative.org/wiki/view/Factor/Learning">start learning</a> the language!</p>
+       <p>This package was built from GIT ID <t:xml t:name="git-id" />.</p>
 
-    <h1>Build machine information</h1>
+       <p>Once you download Factor, you can <a href="http://concatenative.org/wiki/view/Factor/Learning">start learning</a> the language!</p>
 
-    <table border="1">
-      <tr><td>Host name:</td><td><t:xml t:name="host-name" /></td></tr>
-      <tr><td>Last heartbeat:</td><td><t:label t:name="current-timestamp" /></td></tr>
-      <tr><td>Current status:</td><td><t:xml t:name="status" /></td></tr>
-      <tr><td>Last build:</td><td><t:xml t:name="last-build" /></td></tr>
-      <tr><td>Last clean build:</td><td><t:xml t:name="last-clean-build" /></td></tr>
-      <tr><td>Binaries:</td><td><t:xml t:name="binaries" /></td></tr>
-      <tr><td>Clean images:</td><td><t:xml t:name="clean-images" /></td></tr>
-    </table>
+       <h1>Build machine information</h1>
 
-    <p><t:xml t:name="last-report" /></p>
-  </body>
-</html>
+       <table border="1">
+               <tr><td>Host name:</td><td><t:xml t:name="host-name" /></td></tr>
+               <tr><td>Last heartbeat:</td><td><t:label t:name="current-timestamp" /></td></tr>
+               <tr><td>Current status:</td><td><t:xml t:name="status" /></td></tr>
+               <tr><td>Last build:</td><td><t:xml t:name="last-build" /></td></tr>
+               <tr><td>Last clean build:</td><td><t:xml t:name="last-clean-build" /></td></tr>
+               <tr><td>Binaries:</td><td><t:xml t:name="binaries" /></td></tr>
+               <tr><td>Clean images:</td><td><t:xml t:name="clean-images" /></td></tr>
+       </table>
+
+       <p><t:xml t:name="last-report" /></p>
 
 </t:chloe>
index 286a9308b644bed0d0abb5f9fe9c366a1acfcf9e..ffb485e1730fad8dc598cfb237ef0fe188800771 100644 (file)
@@ -5,25 +5,19 @@
 
 <t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
 
-<html xmlns="http://www.w3.org/1999/xhtml">
-  <head>
-    <link rel="stylesheet" href="http://factorcode.org/css/master.css" type="text/css" media="screen" title="no title" charset="utf-8" />
-    <title>Factor binary package for <t:label t:name="platform" /></title>
-  </head>
-  <body>
-    <div><img src="http://factorcode.org/graphics/logo.png" alt="Logo" /></div>
+       <t:title>Factor binary package for <t:label t:name="platform" /></t:title>
 
-    <h1>Factor binary package for <t:label t:name="platform" /></h1>
+       <div><img src="http://factorcode.org/graphics/logo.png" alt="Logo" /></div>
 
-    <p>Requirements:</p>
-    <t:xml t:name="requirements" />
+       <h1>Factor binary package for <t:label t:name="platform" /></h1>
 
-    <h2>Download <t:xml t:name="release" /></h2>
+       <p>Requirements:</p>
+       <t:xml t:name="requirements" />
 
-    <p>This release was built from GIT ID <t:xml t:name="git-id" />.</p>
+       <h2>Download <t:xml t:name="release" /></h2>
 
-    <p>Once you download Factor, you can <a href="http://concatenative.org/wiki/view/Factor/Learning">start learning</a> the language!</p>
-  </body>
-</html>
+       <p>This release was built from GIT ID <t:xml t:name="git-id" />.</p>
+
+       <p>Once you download Factor, you can <a href="http://concatenative.org/wiki/view/Factor/Learning">start learning</a> the language!</p>
 
 </t:chloe>
index 4ff3567bd2ca9a2ef6d5595a66c9c7024e99c798..60a268435e69b59c0dde6be1a540930671939831 100644 (file)
@@ -14,4 +14,6 @@
        <t:xml t:name="package-grid" />
 </table>
 
+<p>Stable and development releases are built and uploaded by the <a href="http://concatenative.org/wiki/view/Factor/Build farm">build farm</a>. Follow <a href="http://twitter.com/FactorBuilds">@FactorBuilds</a> on Twitter to receive notifications. If you're curious, take a look at the <t:a t:href="$mason-app/dashboard">build farm dashboard</t:a>.</p>
+
 </t:chloe>
index 9c861e1345783097009cceb67b81fc06b2344cc3..c2973070cccc645edb4186aa92d26af6a6e2fc21 100644 (file)
@@ -45,12 +45,6 @@ CONSTANT: cpus
         </table>
     XML] ;
 
-: package-url ( builder -- url )
-    [ URL" $mason-app/package" ] dip
-    [ os>> "os" set-query-param ]
-    [ cpu>> "cpu" set-query-param ] bi
-    adjust-url ;
-
 : package-date ( filename -- date )
     "." split1 drop 16 tail* 6 head* ;
 
@@ -72,12 +66,6 @@ CONSTANT: cpus
         ] with-mason-db
     ] >>display ;
 
-: release-url ( builder -- url )
-    [ URL" $mason-app/release" ] dip
-    [ os>> "os" set-query-param ]
-    [ cpu>> "cpu" set-query-param ] bi
-    adjust-url ;
-
 : release-version ( filename -- release )
     ".tar.gz" ?tail drop ".zip" ?tail drop ".dmg" ?tail drop
     "-" split1-last nip ;
diff --git a/extra/webapps/mason/increment-counter/increment-counter.factor b/extra/webapps/mason/increment-counter/increment-counter.factor
new file mode 100644 (file)
index 0000000..75287ab
--- /dev/null
@@ -0,0 +1,14 @@
+! Copyright (C) 2010 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors furnace.actions math.parser
+http.server.responses mason.server ;
+IN: webapps.mason.increment-counter
+
+: <increment-counter-action> ( -- action )
+    <action>
+    [
+        [
+            increment-counter-value
+            number>string "text/plain" <content>
+        ] with-mason-db
+    ] >>submit ;
diff --git a/extra/webapps/mason/make-release.xml b/extra/webapps/mason/make-release.xml
deleted file mode 100644 (file)
index 7143d81..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version='1.0' ?>
-
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
-<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
-
-<html xmlns="http://www.w3.org/1999/xhtml">
-  <head>
-    <title>Make release</title>
-  </head>
-  <body>
-    <t:form t:action="$mason-app/make-release">
-       <table>
-               <tr><td>Version:</td><td><t:field t:name="version" /></td></tr>
-               <tr><td>Announcement URL:</td><td><t:field t:name="announcement-url" /></td></tr>
-       </table>
-
-       <p><button type="submit">Go</button></p>
-    </t:form>
-  </body>
-</html>
-
-</t:chloe>
index e7cd13a8951a980818443a30cb35ab5ce5e583cb..2668a290dbbd18617f5af418af1b4e332330c5e8 100644 (file)
@@ -5,7 +5,7 @@ http.server.responses mason.server mason.version validators ;
 IN: webapps.mason.make-release
 
 : <make-release-action> ( -- action )
-    <page-action>
+    <action>
     [
         {
             { "version" [ v-one-line ] }
index 81eb36a17dbfbf85e71d09b3ce77f52feab8a714..9e871c48a9ea5aca1277a879d15eabbcfcb71441 100644 (file)
@@ -1,17 +1,24 @@
 ! Copyright (C) 2009, 2010 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: accessors furnace.auth furnace.db
+USING: accessors furnace.actions furnace.auth furnace.db
 http.server.dispatchers mason.server webapps.mason.grids
-webapps.mason.make-release webapps.mason.package
-webapps.mason.release webapps.mason.report
-webapps.mason.downloads webapps.mason.status-update ;
+webapps.mason.package webapps.mason.release webapps.mason.report
+webapps.mason.downloads webapps.mason.counter
+webapps.mason.status-update webapps.mason.docs-update
+webapps.mason.dashboard webapps.mason.make-release
+webapps.mason.increment-counter ;
 IN: webapps.mason
 
 TUPLE: mason-app < dispatcher ;
 
-SYMBOL: can-make-releases?
+SYMBOL: build-engineer?
 
-can-make-releases? define-capability
+build-engineer? define-capability
+
+: <mason-protected> ( responder -- responder' )
+    <protected>
+        "access the build farm dashboard" >>description
+        { build-engineer? } >>capabilities ;
 
 : <mason-app> ( -- dispatcher )
     mason-app new-dispatcher
@@ -30,12 +37,24 @@ can-make-releases? define-capability
         { mason-app "downloads" } >>template
         "downloads" add-responder
 
-    <make-release-action>
-        { mason-app "make-release" } >>template
-        <protected>
-            "make releases" >>description
-            { can-make-releases? } >>capabilities
-        "make-release" add-responder
-
     <status-update-action>
-        "status-update" add-responder ;
+        "status-update" add-responder
+
+    <docs-update-action>
+        "docs-update" add-responder
+
+    <counter-action>
+        "counter" add-responder
+
+    <dispatcher>
+        <dashboard-action>
+            { mason-app "dashboard" } >>template
+            "" add-responder
+
+        <make-release-action> <mason-protected>
+            "make-release" add-responder
+
+        <increment-counter-action> <mason-protected>
+            "increment-counter" add-responder
+
+    "dashboard" add-responder ;
index 5156b1ef7049db3d6386841235aa5543e5dff8e7..e19d40e1970a8f1373de7dd59ac0a095cc71d4f3 100644 (file)
@@ -2,7 +2,7 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors calendar combinators db.tuples furnace.actions
 furnace.redirection html.forms http.server.responses io kernel
-mason.config mason.server namespaces validators ;
+mason.server namespaces validators webapps.mason.utils ;
 IN: webapps.mason.status-update
 
 : find-builder ( -- builder )
@@ -56,19 +56,16 @@ IN: webapps.mason.status-update
             { "message" [ v-one-line ] }
             { "arg" [ [ v-one-line ] v-optional ] }
             { "report" [ ] }
-            { "secret" [ v-one-line ] }
         } validate-params
 
-        "secret" value status-secret get = [ validation-failed ] unless
+        validate-secret
     ] >>validate
 
     [
         [
-            [
-                find-builder
-                now >>current-timestamp
-                [ update-builder ] [ update-tuple ] bi
-            ] with-mason-db
-            "OK" "text/html" <content>
-        ] if-secure
+            find-builder
+            now >>current-timestamp
+            [ update-builder ] [ update-tuple ] bi
+        ] with-mason-db
+        "OK" "text/plain" <content>
     ] >>submit ;
index ad56737bc1cb91299a312ae9c19ee70446522147..e450d33f1e3dc09df694dd108998af50361e4169 100644 (file)
@@ -1,8 +1,9 @@
 ! Copyright (C) 2010 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors arrays assocs db.tuples furnace.actions
-html.forms kernel mason.server mason.version.data sequences
-validators xml.syntax ;
+furnace.utilities html.forms kernel mason.config mason.server
+mason.version.data namespaces sequences validators xml.syntax
+urls ;
 IN: webapps.mason.utils
 
 : link ( url label -- xml )
@@ -41,3 +42,20 @@ IN: webapps.mason.utils
 
 : download-url ( string -- string' )
     "http://downloads.factorcode.org/" prepend ;
+
+: package-url ( builder -- url )
+    [ URL" $mason-app/package" ] dip
+    [ os>> "os" set-query-param ]
+    [ cpu>> "cpu" set-query-param ] bi
+    adjust-url ;
+
+: release-url ( builder -- url )
+    [ URL" $mason-app/release" ] dip
+    [ os>> "os" set-query-param ]
+    [ cpu>> "cpu" set-query-param ] bi
+    adjust-url ;
+
+: validate-secret ( -- )
+    { { "secret" [ v-one-line ] } } validate-params
+    "secret" value status-secret get =
+    [ validation-failed ] unless ;
index c0cd601af5ec9306b9663df65412b6c9e1b553dd..700cf56e20535d22afb919a56a28db6fcbb95a09 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel sequences accessors namespaces combinators words
-assocs db.tuples arrays splitting strings validators urls
+assocs db.tuples arrays splitting strings validators urls fry
 html.forms
 html.components
 furnace
@@ -158,8 +158,10 @@ can-administer-users? define-capability
         "administer users" >>description
         { can-administer-users? } >>capabilities ;
 
-: make-admin ( username -- )
-    <user>
-    select-tuple
-    [ can-administer-users? suffix ] change-capabilities
+: give-capability ( username capability -- )
+    [ <user> select-tuple ] dip
+    '[ _ suffix ] change-capabilities
     update-tuple ;
+
+: make-admin ( username -- )
+    can-administer-users? give-capability ;
index efa4c4b6354530f1e540532a292535e58777d2ed..afcaff52f994653adfb070a91b2ddc8e3381fd5c 100644 (file)
@@ -25,12 +25,15 @@ webapps.planet
 webapps.wiki
 webapps.user-admin
 webapps.help
-webapps.mason ;
+webapps.mason
+mason.server ;
 IN: websites.concatenative
 
 : test-db ( -- db ) "resource:test.db" <sqlite-db> ;
 
 : init-factor-db ( -- )
+    mason-db [ init-mason-db ] with-db
+
     test-db [
         init-furnace-tables
 
@@ -86,7 +89,7 @@ SYMBOL: dh-file
         <user-admin> <login-config> <factor-boilerplate> "user-admin" add-responder
         <pastebin> <factor-recaptcha> <login-config> <factor-boilerplate> "pastebin" add-responder
         <planet> <login-config> <factor-boilerplate> "planet" add-responder
-        <mason-app> <login-config> "mason" add-responder
+        <mason-app> <login-config> <factor-boilerplate> "mason" add-responder
         "/tmp/docs/" <help-webapp> "docs" add-responder
     test-db <alloy>
     main-responder set-global ;
@@ -105,7 +108,7 @@ SYMBOL: dh-file
         <login-config> <factor-boilerplate> test-db <alloy> "concatenative.org" add-responder
         <pastebin> <factor-recaptcha> <login-config> <factor-boilerplate> test-db <alloy> "paste.factorcode.org" add-responder
         <planet> <login-config> <factor-boilerplate> test-db <alloy> "planet.factorcode.org" add-responder
-        <mason-app> <login-config> test-db <alloy> "builds.factorcode.org" add-responder
+        <mason-app> <login-config> <factor-boilerplate> test-db <alloy> "builds.factorcode.org" add-responder
         home "docs" append-path <help-webapp> "docs.factorcode.org" add-responder
         home "cgi" append-path <gitweb> "gitweb.factorcode.org" add-responder
     main-responder set-global ;
index c832ca792faf4e1eee2a9397780f87fe254347cf..c747592f42d2e4fae7beeb68818f6461e0a7f8cc 100644 (file)
@@ -22,15 +22,17 @@ void factor_vm::collect_aging()
 
                to_tenured_collector collector(this);
 
-               current_gc->event->started_card_scan();
+               gc_event *event = current_gc->event;
+
+               if(event) event->started_card_scan();
                collector.trace_cards(data->tenured,
                        card_points_to_aging,
                        full_unmarker());
-               current_gc->event->ended_card_scan(collector.cards_scanned,collector.decks_scanned);
+               if(event) event->ended_card_scan(collector.cards_scanned,collector.decks_scanned);
 
-               current_gc->event->started_code_scan();
+               if(event) event->started_code_scan();
                collector.trace_code_heap_roots(&code->points_to_aging);
-               current_gc->event->ended_code_scan(collector.code_blocks_scanned);
+               if(event) event->ended_code_scan(collector.code_blocks_scanned);
 
                collector.tenure_reachable_objects();
        }
index 64c17d8661ccd2e3d033d7fbfa23ed8455530028..d5155d2e6ea3c1dd50959ba87b8b84ef35abbe63 100755 (executable)
@@ -127,6 +127,23 @@ void factor_vm::set_frame_offset(stack_frame *frame, cell offset)
                FRAME_RETURN_ADDRESS(frame,this) = entry_point + offset;
 }
 
+void factor_vm::scrub_return_address()
+{
+       stack_frame *top = ctx->callstack_top;
+       stack_frame *bottom = ctx->callstack_bottom;
+       stack_frame *frame = bottom - 1;
+
+       while(frame >= top && frame_successor(frame) >= top)
+               frame = frame_successor(frame);
+
+       set_frame_offset(frame,0);
+
+#ifdef FACTOR_DEBUG
+       /* Doing a GC here triggers all kinds of funny errors */
+       primitive_compact_gc();
+#endif
+}
+
 cell factor_vm::frame_scan(stack_frame *frame)
 {
        switch(frame_type(frame))
index 9d26062a5c498895b9b7ec2f527f26be4118284b..343a61b8badfd2faa17f92af0b1c40e4565b5304 100644 (file)
@@ -190,7 +190,9 @@ void factor_vm::update_code_roots_for_compaction()
 /* Compact data and code heaps */
 void factor_vm::collect_compact_impl(bool trace_contexts_p)
 {
-       current_gc->event->started_compaction();
+       gc_event *event = current_gc->event;
+
+       if(event) event->started_compaction();
 
        tenured_space *tenured = data->tenured;
        mark_bits<object> *data_forwarding_map = &tenured->state;
@@ -232,7 +234,7 @@ void factor_vm::collect_compact_impl(bool trace_contexts_p)
        update_code_roots_for_compaction();
        callbacks->update();
 
-       current_gc->event->ended_compaction();
+       if(event) event->ended_compaction();
 }
 
 struct code_compaction_fixup {
old mode 100644 (file)
new mode 100755 (executable)
index e07e343..9f4c827
@@ -19,11 +19,29 @@ void factor_vm::c_to_factor(cell quot)
        c_to_factor_func(quot);
 }
 
+template<typename Func> Func factor_vm::get_entry_point(cell n)
+{
+       /* We return word->code->entry_point() and not word->entry_point,
+       because if profiling is enabled, we don't want to go through the
+       entry point's profiling stub. This clobbers registers, since entry
+       points use the C ABI and not the Factor ABI. */
+       tagged<word> entry_point_word(special_objects[n]);
+       return (Func)entry_point_word->code->entry_point();
+}
+
 void factor_vm::unwind_native_frames(cell quot, stack_frame *to)
 {
-       tagged<word> unwind_native_frames_word(special_objects[UNWIND_NATIVE_FRAMES_WORD]);
-       unwind_native_frames_func_type unwind_native_frames_func = (unwind_native_frames_func_type)unwind_native_frames_word->entry_point;
-       unwind_native_frames_func(quot,to);
+       get_entry_point<unwind_native_frames_func_type>(UNWIND_NATIVE_FRAMES_WORD)(quot,to);
+}
+
+cell factor_vm::get_fpu_state()
+{
+       return get_entry_point<get_fpu_state_func_type>(GET_FPU_STATE_WORD)();
+}
+
+void factor_vm::set_fpu_state(cell state)
+{
+       get_entry_point<set_fpu_state_func_type>(GET_FPU_STATE_WORD)(state);
 }
 
 }
old mode 100644 (file)
new mode 100755 (executable)
index 873501f..7c7a1b9
@@ -3,5 +3,7 @@ namespace factor
 
 typedef void (* c_to_factor_func_type)(cell quot);
 typedef void (* unwind_native_frames_func_type)(cell quot, stack_frame *to);
+typedef cell (* get_fpu_state_func_type)();
+typedef void (* set_fpu_state_func_type)(cell state);
 
 }
index 61d4a73194015e3821ca2c4fae39648a17b37ab5..6bd34b8442dc79307a9035643d351e74c3090d03 100755 (executable)
@@ -27,10 +27,8 @@ void out_of_memory()
        exit(1);
 }
 
-void factor_vm::throw_error(cell error, stack_frame *stack)
+void factor_vm::throw_error(cell error)
 {
-       assert(stack);
-
        /* If the error handler is set, we rewind any C stack frames and
        pass the error to user-space. */
        if(!current_gc && to_boolean(special_objects[ERROR_HANDLER_QUOT]))
@@ -49,7 +47,8 @@ void factor_vm::throw_error(cell error, stack_frame *stack)
 
                ctx->push(error);
 
-               unwind_native_frames(special_objects[ERROR_HANDLER_QUOT],stack);
+               unwind_native_frames(special_objects[ERROR_HANDLER_QUOT],
+                       ctx->callstack_top);
        }
        /* Error was thrown in early startup before error handler is set, just
        crash. */
@@ -63,16 +62,10 @@ void factor_vm::throw_error(cell error, stack_frame *stack)
        }
 }
 
-void factor_vm::general_error(vm_error_type error, cell arg1, cell arg2, stack_frame *stack)
-{
-       throw_error(allot_array_4(special_objects[OBJ_ERROR],
-               tag_fixnum(error),arg1,arg2),stack);
-}
-
 void factor_vm::general_error(vm_error_type error, cell arg1, cell arg2)
 {
        throw_error(allot_array_4(special_objects[OBJ_ERROR],
-               tag_fixnum(error),arg1,arg2),ctx->callstack_top);
+               tag_fixnum(error),arg1,arg2));
 }
 
 void factor_vm::type_error(cell type, cell tagged)
@@ -85,29 +78,29 @@ void factor_vm::not_implemented_error()
        general_error(ERROR_NOT_IMPLEMENTED,false_object,false_object);
 }
 
-void factor_vm::memory_protection_error(cell addr, stack_frame *stack)
+void factor_vm::memory_protection_error(cell addr)
 {
        /* Retain and call stack underflows are not supposed to happen */
 
        if(ctx->datastack_seg->underflow_p(addr))
-               general_error(ERROR_DATASTACK_UNDERFLOW,false_object,false_object,stack);
+               general_error(ERROR_DATASTACK_UNDERFLOW,false_object,false_object);
        else if(ctx->datastack_seg->overflow_p(addr))
-               general_error(ERROR_DATASTACK_OVERFLOW,false_object,false_object,stack);
+               general_error(ERROR_DATASTACK_OVERFLOW,false_object,false_object);
        else if(ctx->retainstack_seg->underflow_p(addr))
-               general_error(ERROR_RETAINSTACK_UNDERFLOW,false_object,false_object,stack);
+               general_error(ERROR_RETAINSTACK_UNDERFLOW,false_object,false_object);
        else if(ctx->retainstack_seg->overflow_p(addr))
-               general_error(ERROR_RETAINSTACK_OVERFLOW,false_object,false_object,stack);
+               general_error(ERROR_RETAINSTACK_OVERFLOW,false_object,false_object);
        else if(ctx->callstack_seg->underflow_p(addr))
-               general_error(ERROR_CALLSTACK_OVERFLOW,false_object,false_object,stack);
+               general_error(ERROR_CALLSTACK_OVERFLOW,false_object,false_object);
        else if(ctx->callstack_seg->overflow_p(addr))
-               general_error(ERROR_CALLSTACK_UNDERFLOW,false_object,false_object,stack);
+               general_error(ERROR_CALLSTACK_UNDERFLOW,false_object,false_object);
        else
-               general_error(ERROR_MEMORY,from_unsigned_cell(addr),false_object,stack);
+               general_error(ERROR_MEMORY,from_unsigned_cell(addr),false_object);
 }
 
-void factor_vm::signal_error(cell signal, stack_frame *stack)
+void factor_vm::signal_error(cell signal)
 {
-       general_error(ERROR_SIGNAL,from_unsigned_cell(signal),false_object,stack);
+       general_error(ERROR_SIGNAL,from_unsigned_cell(signal),false_object);
 }
 
 void factor_vm::divide_by_zero_error()
@@ -115,9 +108,9 @@ void factor_vm::divide_by_zero_error()
        general_error(ERROR_DIVIDE_BY_ZERO,false_object,false_object);
 }
 
-void factor_vm::fp_trap_error(unsigned int fpu_status, stack_frame *stack)
+void factor_vm::fp_trap_error(unsigned int fpu_status)
 {
-       general_error(ERROR_FP_TRAP,tag_fixnum(fpu_status),false_object,stack);
+       general_error(ERROR_FP_TRAP,tag_fixnum(fpu_status),false_object);
 }
 
 /* For testing purposes */
@@ -128,7 +121,8 @@ void factor_vm::primitive_unimplemented()
 
 void factor_vm::memory_signal_handler_impl()
 {
-       memory_protection_error(signal_fault_addr,signal_callstack_top);
+       scrub_return_address();
+       memory_protection_error(signal_fault_addr);
 }
 
 void memory_signal_handler_impl()
@@ -138,7 +132,8 @@ void memory_signal_handler_impl()
 
 void factor_vm::misc_signal_handler_impl()
 {
-       signal_error(signal_number,signal_callstack_top);
+       scrub_return_address();
+       signal_error(signal_number);
 }
 
 void misc_signal_handler_impl()
@@ -148,7 +143,11 @@ void misc_signal_handler_impl()
 
 void factor_vm::fp_signal_handler_impl()
 {
-       fp_trap_error(signal_fpu_status,signal_callstack_top);
+       /* Clear pending exceptions to avoid getting stuck in a loop */
+       set_fpu_state(get_fpu_state());
+
+       scrub_return_address();
+       fp_trap_error(signal_fpu_status);
 }
 
 void fp_signal_handler_impl()
index 6a6d7f55f923db1b396cb7ac838c115656186973..3f85c71a05365a60aeb2253cc6867151057dfe53 100755 (executable)
@@ -23,7 +23,7 @@ void factor_vm::default_parameters(vm_parameters *p)
        p->callstack_size = 128 * sizeof(cell);
 #endif
 
-       p->code_size = 8 * sizeof(cell);
+       p->code_size = 64;
        p->young_size = sizeof(cell) / 4;
        p->aging_size = sizeof(cell) / 2;
        p->tenured_size = 24 * sizeof(cell);
index 19d8b576a5bcbf7b77cb7ca8ec50814276ae1628..852c058bd255d2e0075c9384041a8a48a959be8b 100644 (file)
@@ -92,15 +92,17 @@ void factor_vm::collect_mark_impl(bool trace_contexts_p)
 
 void factor_vm::collect_sweep_impl()
 {
-       current_gc->event->started_data_sweep();
+       gc_event *event = current_gc->event;
+
+       if(event) event->started_data_sweep();
        data->tenured->sweep();
-       current_gc->event->ended_data_sweep();
+       if(event) event->ended_data_sweep();
 
        update_code_roots_for_sweep();
 
-       current_gc->event->started_code_sweep();
+       if(event) event->started_code_sweep();
        code->allocator->sweep();
-       current_gc->event->ended_code_sweep();
+       if(event) event->ended_code_sweep();
 }
 
 void factor_vm::collect_full(bool trace_contexts_p)
@@ -110,14 +112,12 @@ void factor_vm::collect_full(bool trace_contexts_p)
 
        if(data->low_memory_p())
        {
-               current_gc->op = collect_growing_heap_op;
-               current_gc->event->op = collect_growing_heap_op;
+               set_current_gc_op(collect_growing_heap_op);
                collect_growing_heap(0,trace_contexts_p);
        }
        else if(data->high_fragmentation_p())
        {
-               current_gc->op = collect_compact_op;
-               current_gc->event->op = collect_compact_op;
+               set_current_gc_op(collect_compact_op);
                collect_compact_impl(trace_contexts_p);
        }
 
index 766940a2d7160ab1152446c3b95a5b4f9ea3c72d..0de3dac91f6d480c3d1d56eae3186b6e5afcccfd 100755 (executable)
--- a/vm/gc.cpp
+++ b/vm/gc.cpp
@@ -80,23 +80,33 @@ void gc_event::ended_gc(factor_vm *parent)
        total_time = (cell)(nano_count() - start_time);
 }
 
-gc_state::gc_state(gc_op op_, factor_vm *parent) : op(op_), start_time(nano_count())
+gc_state::gc_state(gc_op op_, factor_vm *parent) : op(op_)
 {
-       event = new gc_event(op,parent);
+       if(parent->gc_events)
+       {
+               event = new gc_event(op,parent);
+               start_time = nano_count();
+       }
+       else
+               event = NULL;
 }
 
 gc_state::~gc_state()
 {
-       delete event;
-       event = NULL;
+       if(event)
+       {
+               delete event;
+               event = NULL;
+       }
 }
 
 void factor_vm::end_gc()
 {
-       current_gc->event->ended_gc(this);
-       if(gc_events) gc_events->push_back(*current_gc->event);
-       delete current_gc->event;
-       current_gc->event = NULL;
+       if(gc_events)
+       {
+               current_gc->event->ended_gc(this);
+               gc_events->push_back(*current_gc->event);
+       }
 }
 
 void factor_vm::start_gc_again()
@@ -123,7 +133,14 @@ void factor_vm::start_gc_again()
                break;
        }
 
-       current_gc->event = new gc_event(current_gc->op,this);
+       if(gc_events)
+               current_gc->event = new gc_event(current_gc->op,this);
+}
+
+void factor_vm::set_current_gc_op(gc_op op)
+{
+       current_gc->op = op;
+       if(gc_events) current_gc->event->op = op;
 }
 
 void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
@@ -139,7 +156,7 @@ void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
        {
                try
                {
-                       current_gc->event->op = current_gc->op;
+                       if(gc_events) current_gc->event->op = current_gc->op;
 
                        switch(current_gc->op)
                        {
@@ -150,8 +167,7 @@ void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
                                collect_aging();
                                if(data->high_fragmentation_p())
                                {
-                                       current_gc->op = collect_full_op;
-                                       current_gc->event->op = collect_full_op;
+                                       set_current_gc_op(collect_full_op);
                                        collect_full(trace_contexts_p);
                                }
                                break;
@@ -159,8 +175,7 @@ void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
                                collect_to_tenured();
                                if(data->high_fragmentation_p())
                                {
-                                       current_gc->op = collect_full_op;
-                                       current_gc->event->op = collect_full_op;
+                                       set_current_gc_op(collect_full_op);
                                        collect_full(trace_contexts_p);
                                }
                                break;
index f6e9a875a63c04bbf165b155f9421885af6f89a0..76029d81ee851ab4b499eafc35822bd77c93d2e7 100755 (executable)
--- a/vm/gc.hpp
+++ b/vm/gc.hpp
@@ -28,7 +28,7 @@ struct gc_event {
        cell compaction_time;
        u64 temp_time;
 
-       explicit gc_event(gc_op op_, factor_vm *parent);
+       gc_event(gc_op op_, factor_vm *parent);
        void started_card_scan();
        void ended_card_scan(cell cards_scanned_, cell decks_scanned_);
        void started_code_scan();
old mode 100644 (file)
new mode 100755 (executable)
index af14c3a..f87c0c8
@@ -37,7 +37,7 @@ void factor_vm::call_fault_handler(
 {
        MACH_STACK_POINTER(thread_state) = (cell)fix_callstack_top((stack_frame *)MACH_STACK_POINTER(thread_state));
 
-       signal_callstack_top = (stack_frame *)MACH_STACK_POINTER(thread_state);
+       ctx->callstack_top = (stack_frame *)MACH_STACK_POINTER(thread_state);
 
        /* Now we point the program counter at the right handler function. */
        if(exception == EXC_BAD_ACCESS)
index 062aa6aed33294b8f4b0bf092eefaabfc848a52b..7ea81391b25a8f2c252b3b37e957896f00ec0434 100644 (file)
@@ -18,7 +18,9 @@ void factor_vm::collect_nursery()
        collector.trace_roots();
        collector.trace_contexts();
 
-       current_gc->event->started_card_scan();
+       gc_event *event = current_gc->event;
+
+       if(event) event->started_card_scan();
        collector.trace_cards(data->tenured,
                card_points_to_nursery,
                simple_unmarker(card_points_to_nursery));
@@ -28,11 +30,11 @@ void factor_vm::collect_nursery()
                        card_points_to_nursery,
                        full_unmarker());
        }
-       current_gc->event->ended_card_scan(collector.cards_scanned,collector.decks_scanned);
+       if(event) event->ended_card_scan(collector.cards_scanned,collector.decks_scanned);
 
-       current_gc->event->started_code_scan();
+       if(event) event->started_code_scan();
        collector.trace_code_heap_roots(&code->points_to_nursery);
-       current_gc->event->ended_code_scan(collector.code_blocks_scanned);
+       if(event) event->ended_code_scan(collector.code_blocks_scanned);
 
        collector.cheneys_algorithm();
 
old mode 100644 (file)
new mode 100755 (executable)
index 8d883ec..41265cd
@@ -55,6 +55,8 @@ enum special_object {
        C_TO_FACTOR_WORD,
        LAZY_JIT_COMPILE_WORD,
        UNWIND_NATIVE_FRAMES_WORD,
+       GET_FPU_STATE_WORD,
+       SET_FPU_STATE_WORD,
 
        /* Incremented on every modify-code-heap call; invalidates call( inline
        caching */
old mode 100644 (file)
new mode 100755 (executable)
index e95b84f..2e4aed4
@@ -118,7 +118,7 @@ void factor_vm::dispatch_signal(void *uap, void (handler)())
        UAP_STACK_POINTER(uap) = (UAP_STACK_POINTER_TYPE)fix_callstack_top((stack_frame *)UAP_STACK_POINTER(uap));
        UAP_PROGRAM_COUNTER(uap) = (cell)handler;
 
-       signal_callstack_top = (stack_frame *)UAP_STACK_POINTER(uap);
+       ctx->callstack_top = (stack_frame *)UAP_STACK_POINTER(uap);
 }
 
 void memory_signal_handler(int signal, siginfo_t *siginfo, void *uap)
@@ -135,6 +135,10 @@ void misc_signal_handler(int signal, siginfo_t *siginfo, void *uap)
        vm->dispatch_signal(uap,factor::misc_signal_handler_impl);
 }
 
+void ignore_signal_handler(int signal, siginfo_t *siginfo, void *uap)
+{
+}
+
 void fpe_signal_handler(int signal, siginfo_t *siginfo, void *uap)
 {
        factor_vm *vm = current_vm();
@@ -206,9 +210,13 @@ void factor_vm::unix_init_signals()
        sigaction_safe(SIGQUIT,&misc_sigaction,NULL);
        sigaction_safe(SIGILL,&misc_sigaction,NULL);
 
+       /* We don't use SA_IGN here because then the ignore action is inherited
+       by subprocesses, which we don't want. There is a unit test in
+       io.launcher.unix for this. */
        memset(&ignore_sigaction,0,sizeof(struct sigaction));
        sigemptyset(&ignore_sigaction.sa_mask);
-       ignore_sigaction.sa_handler = SIG_IGN;
+       ignore_sigaction.sa_sigaction = ignore_signal_handler;
+       ignore_sigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
        sigaction_safe(SIGPIPE,&ignore_sigaction,NULL);
 }
 
index c774707a767951ee0a9ecfe2efb81d632c13c7ae..2c7dde9c617d3ece6d0a2007964987cb92619513 100644 (file)
@@ -37,9 +37,6 @@ typedef pthread_t THREADHANDLE;
 THREADHANDLE start_thread(void *(*start_routine)(void *),void *args);
 inline static THREADHANDLE thread_id() { return pthread_self(); }
 
-void signal_handler(int signal, siginfo_t* siginfo, void* uap);
-void dump_stack_signal(int signal, siginfo_t* siginfo, void* uap);
-
 u64 nano_count();
 void sleep_nanos(u64 nsec);
 void open_console();
index 7fdb882122b0d31368321de7619d3d15a9ca188e..395ab10214b353e5ba988102e95dd37767bc87c1 100755 (executable)
@@ -50,7 +50,7 @@ void sleep_nanos(u64 nsec)
 LONG factor_vm::exception_handler(PEXCEPTION_RECORD e, void *frame, PCONTEXT c, void *dispatch)
 {
        c->ESP = (cell)fix_callstack_top((stack_frame *)c->ESP);
-       signal_callstack_top = (stack_frame *)c->ESP;
+       ctx->callstack_top = (stack_frame *)c->ESP;
 
        switch (e->ExceptionCode)
        {
@@ -72,6 +72,8 @@ LONG factor_vm::exception_handler(PEXCEPTION_RECORD e, void *frame, PCONTEXT c,
                signal_fpu_status = fpu_status(MXCSR(c));
 #else
                signal_fpu_status = fpu_status(X87SW(c) | MXCSR(c));
+
+               /* This seems to have no effect */
                X87SW(c) = 0;
 #endif
                MXCSR(c) &= 0xffffffc0;
index b29affc480ccfbbd3d26d8e2dbf0f8c37b8d593f..4d11cdb27b1797220180fd6987b03baf82cc859f 100644 (file)
@@ -30,15 +30,17 @@ void factor_vm::collect_to_tenured()
        collector.trace_roots();
        collector.trace_contexts();
 
-       current_gc->event->started_card_scan();
+       gc_event *event = current_gc->event;
+
+       if(event) event->started_card_scan();
        collector.trace_cards(data->tenured,
                card_points_to_aging,
                full_unmarker());
-       current_gc->event->ended_card_scan(collector.cards_scanned,collector.decks_scanned);
+       if(event) event->ended_card_scan(collector.cards_scanned,collector.decks_scanned);
 
-       current_gc->event->started_code_scan();
+       if(event) event->started_code_scan();
        collector.trace_code_heap_roots(&code->points_to_aging);
-       current_gc->event->ended_code_scan(collector.code_blocks_scanned);
+       if(event) event->ended_code_scan(collector.code_blocks_scanned);
 
        collector.tenure_reachable_objects();
 
index 6aa3543c8f5c4a6a33a54f66d285abff434efd12..44ac81a70c554b22e29bfd39f1172fd89b765dba 100755 (executable)
--- a/vm/vm.hpp
+++ b/vm/vm.hpp
@@ -49,12 +49,11 @@ struct factor_vm
        /* Is call counting enabled? */
        bool profiling_p;
 
-       /* Global variables used to pass fault handler state from signal handler to
-          user-space */
+       /* Global variables used to pass fault handler state from signal handler
+       to VM */
        cell signal_number;
        cell signal_fault_addr;
        unsigned int signal_fpu_status;
-       stack_frame *signal_callstack_top;
 
        /* GC is off during heap walking */
        bool gc_off;
@@ -168,15 +167,14 @@ struct factor_vm
        void primitive_profiling();
 
        // errors
-       void throw_error(cell error, stack_frame *stack);
-       void general_error(vm_error_type error, cell arg1, cell arg2, stack_frame *stack);
+       void throw_error(cell error);
        void general_error(vm_error_type error, cell arg1, cell arg2);
        void type_error(cell type, cell tagged);
        void not_implemented_error();
-       void memory_protection_error(cell addr, stack_frame *stack);
-       void signal_error(cell signal, stack_frame *stack);
+       void memory_protection_error(cell addr);
+       void signal_error(cell signal);
        void divide_by_zero_error();
-       void fp_trap_error(unsigned int fpu_status, stack_frame *stack);
+       void fp_trap_error(unsigned int fpu_status);
        void primitive_unimplemented();
        void memory_signal_handler_impl();
        void misc_signal_handler_impl();
@@ -301,6 +299,7 @@ struct factor_vm
 
        // gc
        void end_gc();
+       void set_current_gc_op(gc_op op);
        void start_gc_again();
        void update_code_heap_for_minor_gc(std::set<code_block *> *remembered_set);
        void collect_nursery();
@@ -588,6 +587,7 @@ struct factor_vm
        cell frame_scan(stack_frame *frame);
        cell frame_offset(stack_frame *frame);
        void set_frame_offset(stack_frame *frame, cell offset);
+       void scrub_return_address();
        void primitive_callstack_to_array();
        stack_frame *innermost_stack_frame(callstack *stack);
        void primitive_innermost_stack_frame_executing();
@@ -653,7 +653,10 @@ struct factor_vm
 
        // entry points
        void c_to_factor(cell quot);
+       template<typename Func> Func get_entry_point(cell n);
        void unwind_native_frames(cell quot, stack_frame *to);
+       cell get_fpu_state();
+       void set_fpu_state(cell state);
 
        // factor
        void default_parameters(vm_parameters *p);