1
0
mirror of https://github.com/janet-lang/janet synced 2025-11-26 12:14:49 +00:00

Compare commits

..

5 Commits

Author SHA1 Message Date
Calvin Rose
a62d1c35d4 Add some systems that support addchdir. 2025-04-06 16:55:22 -05:00
Calvin Rose
9a737d1fc4 Add ifdefs for various platforms to check for the support of addchdir.
This will need to be expanded but should support most modern systems.
2025-04-06 16:48:32 -05:00
Calvin Rose
03672cc82b Merge branch 'master' into posix-spawn-chdir 2025-04-06 14:58:04 -05:00
Calvin Rose
73af64e6ff Fix signature on windows. 2025-04-06 14:49:54 -05:00
Calvin Rose
2262759751 Add :cd argument to os/execute and os/spawn. 2025-04-06 14:46:23 -05:00
32 changed files with 232 additions and 557 deletions

View File

@@ -1,4 +1,4 @@
image: openbsd/7.6 image: openbsd/7.4
sources: sources:
- https://git.sr.ht/~bakpakin/janet - https://git.sr.ht/~bakpakin/janet
packages: packages:

View File

@@ -25,7 +25,7 @@ jobs:
name: Build and test on Windows name: Build and test on Windows
strategy: strategy:
matrix: matrix:
os: [ windows-latest, windows-2022 ] os: [ windows-latest, windows-2019 ]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout the repository - name: Checkout the repository
@@ -46,7 +46,7 @@ jobs:
name: Build and test on Windows Minimal build name: Build and test on Windows Minimal build
strategy: strategy:
matrix: matrix:
os: [ windows-2022 ] os: [ windows-2019 ]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout the repository - name: Checkout the repository

View File

@@ -2,23 +2,9 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## Unreleased - ??? ## Unreleased - ???
- Add `gcperthread` callback for abstract types. This lets threaded abstracts have a finalizer that is called per thread, as well as a global finalizer.
- Add `JANET_DO_ERROR_*` flags to describe the return value of `janet_dobytes` and `janet_dostring`.
## 1.39.1 - 2025-08-30
- Add support for chdir in os/spawn on older macOS versions
- Expose channels properly in C API
## 1.39.0 - 2025-08-24
- Various bug fixes
- Add `net/socket`
- Add support for illumos OS
- Raise helpful errors for incorrect arguments to `import`.
- Allow configuring `JANET_THREAD_LOCAL` during builds to allow multi-threading on unknown compilers.
- Make `ffi/write` append to a buffer instead of insert at 0 by default. - Make `ffi/write` append to a buffer instead of insert at 0 by default.
- Add `os/getpid` to get the current process id. - Add `os/getpid` to get the current process id.
- Add `:out` option to `os/spawn` to be able to redirect stderr to stdout with pipes. - Add `:out` option to `os/spawn` to be able to redirect stderr to stdout with pipes.
Add `interrupt?` argument to `ev/deadline` to use VM interruptions.
## 1.38.0 - 2025-03-18 ## 1.38.0 - 2025-03-18
- Add `bundle/replace` - Add `bundle/replace`

View File

@@ -47,7 +47,6 @@ SPORK_TAG?=master
HAS_SHARED?=1 HAS_SHARED?=1
DEBUGGER=gdb DEBUGGER=gdb
SONAME_SETTER=-Wl,-soname, SONAME_SETTER=-Wl,-soname,
STRIPFLAGS=-x -S
# For cross compilation # For cross compilation
HOSTCC?=$(CC) HOSTCC?=$(CC)
@@ -55,7 +54,7 @@ HOSTAR?=$(AR)
# Symbols are (optionally) removed later, keep -g as default! # Symbols are (optionally) removed later, keep -g as default!
CFLAGS?=-O2 -g CFLAGS?=-O2 -g
LDFLAGS?=-rdynamic LDFLAGS?=-rdynamic
LIBJANET_LDFLAGS?=$(LDFLAGS) LIBJANET_LDFLAGS?=$(LD_FLAGS)
RUN:=$(RUN) RUN:=$(RUN)
@@ -81,12 +80,6 @@ ifeq ($(UNAME), Darwin)
LDCONFIG:=true LDCONFIG:=true
else ifeq ($(UNAME), Linux) else ifeq ($(UNAME), Linux)
CLIBS:=$(CLIBS) -lrt -ldl CLIBS:=$(CLIBS) -lrt -ldl
else ifeq ($(UNAME), SunOS)
BUILD_CFLAGS+=-D__EXTENSIONS__ -DJANET_NO_NANBOX
BOOT_CFLAGS+=-D__EXTENSIONS__ -DJANET_NO_NANBOX
CLIBS:=-lsocket -lm
STRIPFLAGS=-x
LDCONFIG:=false
endif endif
# For other unix likes, add flags here! # For other unix likes, add flags here!
@@ -220,9 +213,9 @@ build/%.bin.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS) Makefile
######################## ########################
ifeq ($(UNAME), Darwin) ifeq ($(UNAME), Darwin)
SONAME=libjanet.1.40.dylib SONAME=libjanet.1.38.dylib
else else
SONAME=libjanet.so.1.40 SONAME=libjanet.so.1.38
endif endif
ifeq ($(MINGW_COMPILER), clang) ifeq ($(MINGW_COMPILER), clang)
@@ -296,7 +289,7 @@ build/janet-%.tar.gz: $(JANET_TARGET) \
README.md build/c/janet.c build/c/shell.c README.md build/c/janet.c build/c/shell.c
mkdir -p build/$(JANET_DIST_DIR)/bin mkdir -p build/$(JANET_DIST_DIR)/bin
cp $(JANET_TARGET) build/$(JANET_DIST_DIR)/bin/ cp $(JANET_TARGET) build/$(JANET_DIST_DIR)/bin/
strip $(STRIPFLAGS) 'build/$(JANET_DIST_DIR)/bin/janet' strip -x -S 'build/$(JANET_DIST_DIR)/bin/janet'
mkdir -p build/$(JANET_DIST_DIR)/include mkdir -p build/$(JANET_DIST_DIR)/include
cp build/janet.h build/$(JANET_DIST_DIR)/include/ cp build/janet.h build/$(JANET_DIST_DIR)/include/
mkdir -p build/$(JANET_DIST_DIR)/lib/ mkdir -p build/$(JANET_DIST_DIR)/lib/
@@ -343,7 +336,7 @@ build/janet.pc: $(JANET_TARGET)
install: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.pc build/janet.h install: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.pc build/janet.h
mkdir -p '$(DESTDIR)$(BINDIR)' mkdir -p '$(DESTDIR)$(BINDIR)'
cp $(JANET_TARGET) '$(DESTDIR)$(BINDIR)/janet' cp $(JANET_TARGET) '$(DESTDIR)$(BINDIR)/janet'
strip $(STRIPFLAGS) '$(DESTDIR)$(BINDIR)/janet' strip -x -S '$(DESTDIR)$(BINDIR)/janet'
mkdir -p '$(DESTDIR)$(INCLUDEDIR)/janet' mkdir -p '$(DESTDIR)$(INCLUDEDIR)/janet'
cp -r build/janet.h '$(DESTDIR)$(INCLUDEDIR)/janet' cp -r build/janet.h '$(DESTDIR)$(INCLUDEDIR)/janet'
ln -sf ./janet/janet.h '$(DESTDIR)$(INCLUDEDIR)/janet.h' ln -sf ./janet/janet.h '$(DESTDIR)$(INCLUDEDIR)/janet.h'

View File

@@ -213,10 +213,6 @@ gmake install-jpm-git
NetBSD build instructions are the same as the FreeBSD build instructions. NetBSD build instructions are the same as the FreeBSD build instructions.
Alternatively, install the package directly with `pkgin install janet`. Alternatively, install the package directly with `pkgin install janet`.
### illumos
Building on illumos is exactly the same as building on FreeBSD.
### Windows ### Windows
1. Install [Visual Studio](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community&rel=15#) or [Visual Studio Build Tools](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=15#). 1. Install [Visual Studio](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community&rel=15#) or [Visual Studio Build Tools](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=15#).

View File

@@ -49,7 +49,6 @@ for %%f in (src\boot\*.c) do (
) )
%JANET_LINK% /out:build\janet_boot.exe build\boot\*.obj %JANET_LINK% /out:build\janet_boot.exe build\boot\*.obj
@if errorlevel 1 goto :BUILDFAIL @if errorlevel 1 goto :BUILDFAIL
@rem note that there is no default sysroot being baked in
build\janet_boot . > build\c\janet.c build\janet_boot . > build\c\janet.c
@if errorlevel 1 goto :BUILDFAIL @if errorlevel 1 goto :BUILDFAIL

View File

@@ -1,6 +0,0 @@
# Linux only - uses abstract unix domain sockets
(ev/spawn (net/server :unix "@abc123" (fn [conn] (print (:read conn 1024)) (:close conn))))
(ev/sleep 1)
(def s (net/connect :unix "@abc123" :stream))
(:write s "hello")
(:close s)

View File

@@ -1,4 +1,4 @@
@{ @{
:name "sample-dep1" :name "sample-dep1"
:dependencies [{:name "sample-dep2"}] :dependencies ["sample-dep2"]
} }

View File

@@ -214,7 +214,7 @@ Don't execute a script, only compile it to check for errors. Useful for linting
.BR \-m\ syspath .BR \-m\ syspath
Set the dynamic binding :syspath to the string syspath so that Janet will load system modules Set the dynamic binding :syspath to the string syspath so that Janet will load system modules
from a directory different than the default. The default is set when Janet is built, and defaults to from a directory different than the default. The default is set when Janet is built, and defaults to
/usr/local/lib/janet on Linux/Posix. On Windows, there is no default value. This option supersedes JANET_PATH. /usr/local/lib/janet on Linux/Posix, and C:/Janet/Library on Windows. This option supersedes JANET_PATH.
.TP .TP
.BR \-c\ source\ output .BR \-c\ source\ output
@@ -255,7 +255,8 @@ and then arguments to the script.
.RS .RS
The location to look for Janet libraries. This is the only environment variable Janet needs to The location to look for Janet libraries. This is the only environment variable Janet needs to
find native and source code modules. If no JANET_PATH is set, Janet will look in find native and source code modules. If no JANET_PATH is set, Janet will look in
the default location set at compile time. This should be a colon-separated list of directory names on Linux/Posix, and a semicolon-separated list on Windows. Note that a typical setup (i.e. not NixOS / Guix) will only use a single directory. the default location set at compile time. This should be a list of as well as a colon
separate list of such directories.
.RE .RE
.B JANET_PROFILE .B JANET_PROFILE

View File

@@ -20,7 +20,7 @@
project('janet', 'c', project('janet', 'c',
default_options : ['c_std=c99', 'build.c_std=c99', 'b_lundef=false', 'default_library=both'], default_options : ['c_std=c99', 'build.c_std=c99', 'b_lundef=false', 'default_library=both'],
version : '1.40.0') version : '1.38.0')
# Global settings # Global settings
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet') janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
@@ -105,9 +105,6 @@ endif
if get_option('arch_name') != '' if get_option('arch_name') != ''
conf.set('JANET_ARCH_NAME', get_option('arch_name')) conf.set('JANET_ARCH_NAME', get_option('arch_name'))
endif endif
if get_option('thread_local_prefix') != ''
conf.set('JANET_THREAD_LOCAL', get_option('thread_local_prefix'))
endif
jconf = configure_file(output : 'janetconf.h', jconf = configure_file(output : 'janetconf.h',
configuration : conf) configuration : conf)
@@ -281,7 +278,6 @@ test_files = [
'test/suite-corelib.janet', 'test/suite-corelib.janet',
'test/suite-debug.janet', 'test/suite-debug.janet',
'test/suite-ev.janet', 'test/suite-ev.janet',
'test/suite-ev2.janet',
'test/suite-ffi.janet', 'test/suite-ffi.janet',
'test/suite-filewatch.janet', 'test/suite-filewatch.janet',
'test/suite-inttypes.janet', 'test/suite-inttypes.janet',

View File

@@ -30,7 +30,6 @@ option('max_macro_expand', type : 'integer', min : 1, max : 8000, value : 200)
option('stack_max', type : 'integer', min : 8096, max : 0x7fffffff, value : 0x7fffffff) option('stack_max', type : 'integer', min : 8096, max : 0x7fffffff, value : 0x7fffffff)
option('arch_name', type : 'string', value: '') option('arch_name', type : 'string', value: '')
option('thread_local_prefix', type : 'string', value: '')
option('os_name', type : 'string', value: '') option('os_name', type : 'string', value: '')
option('shared', type : 'boolean', value: true) option('shared', type : 'boolean', value: true)
option('cryptorand', type : 'boolean', value: true) option('cryptorand', type : 'boolean', value: true)

View File

@@ -158,7 +158,7 @@
``Define an alias for a keyword that is used as a dynamic binding. The ``Define an alias for a keyword that is used as a dynamic binding. The
alias is a normal, lexically scoped binding that can be used instead of alias is a normal, lexically scoped binding that can be used instead of
a keyword to prevent typos. `defdyn` does not set dynamic bindings or otherwise a keyword to prevent typos. `defdyn` does not set dynamic bindings or otherwise
replace `dyn` and `setdyn`. The alias *must* start and end with the `*` character, usually replace `dyn` and `setdyn`. The alias _must_ start and end with the `*` character, usually
called "earmuffs".`` called "earmuffs".``
[alias & more] [alias & more]
(assert (symbol? alias) "alias must be a symbol") (assert (symbol? alias) "alias must be a symbol")
@@ -290,6 +290,22 @@
(array/concat accum body) (array/concat accum body)
(tuple/slice accum 0)) (tuple/slice accum 0))
(defmacro try
``Try something and catch errors. `body` is any expression,
and `catch` should be a form, the first element of which is a tuple. This tuple
should contain a binding for errors and an optional binding for
the fiber wrapping the body. Returns the result of `body` if no error,
or the result of `catch` if an error.``
[body catch]
(let [[[err fib]] catch
f (gensym)
r (gensym)]
~(let [,f (,fiber/new (fn :try [] ,body) :ie)
,r (,resume ,f)]
(if (,= (,fiber/status ,f) :error)
(do (def ,err ,r) ,(if fib ~(def ,fib ,f)) ,;(tuple/slice catch 1))
,r))))
(defmacro protect (defmacro protect
`Evaluate expressions, while capturing any errors. Evaluates to a tuple `Evaluate expressions, while capturing any errors. Evaluates to a tuple
of two elements. The first element is true if successful, false if an of two elements. The first element is true if successful, false if an
@@ -336,23 +352,6 @@
(tuple 'if $fi $fi ret)))))) (tuple 'if $fi $fi ret))))))
ret) ret)
(defmacro try
``Try something and catch errors. `body` is any expression,
and `catch` should be a form, the first element of which is a tuple. This tuple
should contain a binding for errors and an optional binding for
the fiber wrapping the body. Returns the result of `body` if no error,
or the result of `catch` if an error.``
[body catch]
(assert (and (not (empty? catch)) (indexed? (catch 0))) "the first element of `catch` must be a tuple or array")
(let [[err fib] (catch 0)
r (or err (gensym))
f (or fib (gensym))]
~(let [,f (,fiber/new (fn :try [] ,body) :ie)
,r (,resume ,f)]
(if (,= (,fiber/status ,f) :error)
(do ,;(tuple/slice catch 1))
,r))))
(defmacro with-syms (defmacro with-syms
"Evaluates `body` with each symbol in `syms` bound to a generated, unique symbol." "Evaluates `body` with each symbol in `syms` bound to a generated, unique symbol."
[syms & body] [syms & body]
@@ -1104,9 +1103,8 @@
and use `array/concat` to concatenate the results, but only if and use `array/concat` to concatenate the results, but only if
no `inds` are provided. Multiple data structures can be handled no `inds` are provided. Multiple data structures can be handled
if each `inds` is a data structure and `f` is a function of if each `inds` is a data structure and `f` is a function of
arity one more than the number of `inds`. Note that `f` is only arity one more than the number of `inds`. The resulting array
applied to values at indeces up to the largest index of the has a length that is the shortest of `ind` and each of `inds`.
shortest of `ind` and each of `inds`.
``` ```
[f ind & inds] [f ind & inds]
(def res @[]) (def res @[])
@@ -1145,8 +1143,8 @@
structure `ind`, but only if no `inds` are provided. Multiple structure `ind`, but only if no `inds` are provided. Multiple
data structures can be handled if each `inds` is a data data structures can be handled if each `inds` is a data
structure and `pred` is a function of arity one more than the structure and `pred` is a function of arity one more than the
number of `inds`. The resulting array has a length that is no number of `inds`. The resulting array has a length that is the
longer than the shortest of `ind` and each of `inds`. shortest of `ind` and each of `inds`.
``` ```
[pred ind & inds] [pred ind & inds]
(def res @[]) (def res @[])
@@ -1934,7 +1932,7 @@
that will match any value without creating a binding. that will match any value without creating a binding.
While a symbol pattern will ordinarily match any value, the pattern `(@ <sym>)`, While a symbol pattern will ordinarily match any value, the pattern `(@ <sym>)`,
where `<sym>` is any symbol, will attempt to match `x` against a value where <sym> is any symbol, will attempt to match `x` against a value
already bound to `<sym>`, rather than matching and rebinding it. already bound to `<sym>`, rather than matching and rebinding it.
Any other value pattern will only match if it is equal to `x`. Any other value pattern will only match if it is equal to `x`.
@@ -2575,7 +2573,7 @@
* `:env` -- the environment to compile against - default is the current env * `:env` -- the environment to compile against - default is the current env
* `:source` -- source path for better errors (use keywords for non-paths) - default * `:source` -- source path for better errors (use keywords for non-paths) - default
is `:<anonymous>` is :<anonymous>
* `:on-compile-error` -- callback when compilation fails - default is bad-compile * `:on-compile-error` -- callback when compilation fails - default is bad-compile
@@ -3181,17 +3179,12 @@
use the name of the module as a prefix. One can also use "`:export true`" use the name of the module as a prefix. One can also use "`:export true`"
to re-export the imported symbols. If "`:exit true`" is given as an argument, to re-export the imported symbols. If "`:exit true`" is given as an argument,
any errors encountered at the top level in the module will cause `(os/exit 1)` any errors encountered at the top level in the module will cause `(os/exit 1)`
to be called. Dynamic bindings will NOT be imported. Use :fresh with a truthy to be called. Dynamic bindings will NOT be imported. Use :fresh to bypass the
value to bypass the module cache. Use `:only [foo bar baz]` to only import module cache. Use `:only [foo bar baz]` to only import select bindings into the
select bindings into the current environment.`` current environment.``
[path & args] [path & args]
(assertf (even? (length args)) "args should have even length: %n" args)
(def ps (partition 2 args)) (def ps (partition 2 args))
(def argm (def argm (mapcat (fn [[k v]] [k (case k :as (string v) :only ~(quote ,v) v)]) ps))
(mapcat (fn [[k v]]
(assertf (keyword? k) "expected keyword, got %s: %n" (type k) k)
[k (case k :as (string v) :only ~(quote ,v) v)])
ps))
(tuple import* (string path) ;argm)) (tuple import* (string path) ;argm))
(defmacro use (defmacro use
@@ -3254,10 +3247,12 @@
# Terminal codes for emission/tokenization # Terminal codes for emission/tokenization
(def delimiters (def delimiters
(if has-color (if has-color
{:code ["\e[97m" "\e[39m"] {:underline ["\e[4m" "\e[24m"]
:code ["\e[97m" "\e[39m"]
:italics ["\e[4m" "\e[24m"] :italics ["\e[4m" "\e[24m"]
:bold ["\e[1m" "\e[22m"]} :bold ["\e[1m" "\e[22m"]}
{:code ["`" "`"] {:underline ["_" "_"]
:code ["`" "`"]
:italics ["*" "*"] :italics ["*" "*"]
:bold ["**" "**"]})) :bold ["**" "**"]}))
(def modes @{}) (def modes @{})
@@ -3388,6 +3383,7 @@
(= b (chr `\`)) (do (= b (chr `\`)) (do
(++ token-length) (++ token-length)
(buffer/push token (get line (++ i)))) (buffer/push token (get line (++ i))))
(= b (chr "_")) (delim :underline)
(= b (chr "*")) (= b (chr "*"))
(if (= (chr "*") (get line (+ i 1))) (if (= (chr "*") (get line (+ i 1)))
(do (++ i) (do (++ i)
@@ -3919,14 +3915,8 @@
(compwhen (dyn 'net/listen) (compwhen (dyn 'net/listen)
(defn net/server (defn net/server
`` "Start a server asynchronously with `net/listen` and `net/accept-loop`. Returns the new server stream."
Starts a server with `net/listen`. Runs `net/accept-loop` asynchronously if
`handler` is set and `type` is `:stream` (the default). It is invalid to set
`handler` if `type` is `:datagram`. Returns the new server stream.
``
[host port &opt handler type no-reuse] [host port &opt handler type no-reuse]
(assert (not (and (= type :datagram) handler))
"handler not supported for :datagram servers")
(def s (net/listen host port type no-reuse)) (def s (net/listen host port type no-reuse))
(if handler (if handler
(ev/go (fn [] (net/accept-loop s handler)))) (ev/go (fn [] (net/accept-loop s handler))))
@@ -4305,14 +4295,20 @@
"Install a bundle from the local filesystem. The name of the bundle will be inferred from the bundle, or passed as a parameter :name in `config`." "Install a bundle from the local filesystem. The name of the bundle will be inferred from the bundle, or passed as a parameter :name in `config`."
[path &keys config] [path &keys config]
(def path (bundle-rpath path)) (def path (bundle-rpath path))
(def clean (get config :clean))
(def check (get config :check))
(def s (sep)) (def s (sep))
# Detect bundle name # Check meta file for dependencies and default name
(def infofile-src1 (string path s "bundle" s "info.jdn")) (def infofile-pre-1 (string path s "bundle" s "info.jdn"))
(def infofile-src2 (string path s "info.jdn")) (def infofile-pre (if (fexists infofile-pre-1) infofile-pre-1 (string path s "info.jdn"))) # allow for alias
(def infofile-src (cond (fexists infofile-src1) infofile-src1 (var default-bundle-name nil)
(fexists infofile-src2) infofile-src2)) (when (os/stat infofile-pre :mode)
(def info (-?> infofile-src slurp parse)) (def info (-> infofile-pre slurp parse))
(def bundle-name (get config :name (get info :name))) (def deps (get info :dependencies @[]))
(set default-bundle-name (get info :name))
(def missing (seq [d :in deps :when (not (bundle/installed? d))] (string d)))
(when (next missing) (errorf "missing dependencies %s" (string/join missing ", "))))
(def bundle-name (get config :name default-bundle-name))
(assertf bundle-name "unable to infer bundle name for %v, use :name argument" path) (assertf bundle-name "unable to infer bundle name for %v, use :name argument" path)
(assertf (not (string/check-set "\\/" bundle-name)) (assertf (not (string/check-set "\\/" bundle-name))
"bundle name %v cannot contain path separators" bundle-name) "bundle name %v cannot contain path separators" bundle-name)
@@ -4322,32 +4318,28 @@
# Setup installed paths # Setup installed paths
(prime-bundle-paths) (prime-bundle-paths)
(os/mkdir (bundle-dir bundle-name)) (os/mkdir (bundle-dir bundle-name))
# Copy infofile # Aliases for common bundle/ files
(def infofile-dest (bundle-file bundle-name "info.jdn")) (def bundle.janet (string path s "bundle.janet"))
(when infofile-src (copyfile infofile-src infofile-dest)) (when (fexists bundle.janet) (copyfile bundle.janet (bundle-file bundle-name "init.janet")))
# Copy aliased initfile (when (fexists infofile-pre) (copyfile infofile-pre (bundle-file bundle-name "info.jdn")))
(def initfile-alias (string path s "bundle.janet"))
(def initfile-dest (bundle-file bundle-name "init.janet"))
(when (fexists initfile-alias) (copyfile initfile-alias initfile-dest))
# Copy some files into the new location unconditionally # Copy some files into the new location unconditionally
(def implicit-sources (string path s "bundle")) (def implicit-sources (string path s "bundle"))
(when (= :directory (os/stat implicit-sources :mode)) (when (= :directory (os/stat implicit-sources :mode))
(copyrf implicit-sources (bundle-dir bundle-name))) (copyrf implicit-sources (bundle-dir bundle-name)))
(def man @{:name bundle-name :local-source path :files @[]}) (def man @{:name bundle-name :local-source path :files @[]})
(merge-into man config) (merge-into man config)
(def infofile (bundle-file bundle-name "info.jdn"))
(put man :auto-remove (get config :auto-remove))
(sync-manifest man) (sync-manifest man)
(edefer (do (print "installation error, uninstalling") (bundle/uninstall bundle-name)) (edefer (do (print "installation error, uninstalling") (bundle/uninstall bundle-name))
(when (os/stat infofile-dest :mode) (when (os/stat infofile :mode)
(def info (-> infofile-dest slurp parse)) (def info (-> infofile slurp parse))
(def deps (seq [d :in (get info :dependencies @[])] (def deps (get info :dependencies @[]))
(string (if (dictionary? d) (get d :name) d))))
(def missing (filter (complement bundle/installed?) deps)) (def missing (filter (complement bundle/installed?) deps))
(when (next missing) (when (next missing)
(error (string "missing dependencies " (string/join missing ", ")))) (error (string "missing dependencies " (string/join missing ", "))))
(put man :dependencies deps) (put man :dependencies deps)
(put man :info info)) (put man :info info))
(def clean (get config :clean))
(def check (get config :check))
(def module (get-bundle-module bundle-name)) (def module (get-bundle-module bundle-name))
(def all-hooks (seq [[k v] :pairs module :when (symbol? k) :unless (get v :private)] (keyword k))) (def all-hooks (seq [[k v] :pairs module :when (symbol? k) :unless (get v :private)] (keyword k)))
(put man :hooks all-hooks) (put man :hooks all-hooks)
@@ -4490,10 +4482,8 @@
(errorf "bad path %s - file is a %s" src mode))) (errorf "bad path %s - file is a %s" src mode)))
(defn bundle/add-bin (defn bundle/add-bin
`` `Shorthand for adding scripts during an install. Scripts will be installed to
Shorthand for adding scripts during an install. Scripts will be installed to (string (dyn *syspath*) "/bin") by default and will be set to be executable.`
`(string (dyn *syspath*) "/bin")` by default and will be set to be executable.
``
[manifest src &opt dest chmod-mode] [manifest src &opt dest chmod-mode]
(def s (sep)) (def s (sep))
(default dest (last (string/split s src))) (default dest (last (string/split s src)))
@@ -4638,7 +4628,7 @@
--reinstall (-B) name : Reinstall a bundle by bundle name --reinstall (-B) name : Reinstall a bundle by bundle name
--uninstall (-u) name : Uninstall a bundle by bundle name --uninstall (-u) name : Uninstall a bundle by bundle name
--update-all (-U) : Reinstall all installed bundles --update-all (-U) : Reinstall all installed bundles
--prune (-P) : Uninstall all bundles that are orphaned --prune (-P) : Uninstalled all bundles that are orphaned
--list (-L) : List all installed bundles --list (-L) : List all installed bundles
-- : Stop handling options -- : Stop handling options
```) ```)

View File

@@ -4,16 +4,15 @@
#define JANETCONF_H #define JANETCONF_H
#define JANET_VERSION_MAJOR 1 #define JANET_VERSION_MAJOR 1
#define JANET_VERSION_MINOR 40 #define JANET_VERSION_MINOR 38
#define JANET_VERSION_PATCH 0 #define JANET_VERSION_PATCH 0
#define JANET_VERSION_EXTRA "" #define JANET_VERSION_EXTRA ""
#define JANET_VERSION "1.40.0" #define JANET_VERSION "1.38.0"
/* #define JANET_BUILD "local" */ /* #define JANET_BUILD "local" */
/* These settings all affect linking, so use cautiously. */ /* These settings all affect linking, so use cautiously. */
/* #define JANET_SINGLE_THREADED */ /* #define JANET_SINGLE_THREADED */
/* #define JANET_THREAD_LOCAL _Thread_local */
/* #define JANET_NO_DYNAMIC_MODULES */ /* #define JANET_NO_DYNAMIC_MODULES */
/* #define JANET_NO_NANBOX */ /* #define JANET_NO_NANBOX */
/* #define JANET_API __attribute__((visibility ("default"))) */ /* #define JANET_API __attribute__((visibility ("default"))) */

View File

@@ -88,7 +88,7 @@ void *janet_abstract_threaded(const JanetAbstractType *atype, size_t size) {
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
size_t janet_os_mutex_size(void) { size_t janet_os_mutex_size(void) {
return sizeof(SRWLOCK); return sizeof(CRITICAL_SECTION);
} }
size_t janet_os_rwlock_size(void) { size_t janet_os_rwlock_size(void) {
@@ -96,20 +96,20 @@ size_t janet_os_rwlock_size(void) {
} }
void janet_os_mutex_init(JanetOSMutex *mutex) { void janet_os_mutex_init(JanetOSMutex *mutex) {
InitializeSRWLock((PSRWLOCK) mutex); InitializeCriticalSection((CRITICAL_SECTION *) mutex);
} }
void janet_os_mutex_deinit(JanetOSMutex *mutex) { void janet_os_mutex_deinit(JanetOSMutex *mutex) {
/* no op? */ DeleteCriticalSection((CRITICAL_SECTION *) mutex);
(void) mutex;
} }
void janet_os_mutex_lock(JanetOSMutex *mutex) { void janet_os_mutex_lock(JanetOSMutex *mutex) {
AcquireSRWLockExclusive((PSRWLOCK) mutex); EnterCriticalSection((CRITICAL_SECTION *) mutex);
} }
void janet_os_mutex_unlock(JanetOSMutex *mutex) { void janet_os_mutex_unlock(JanetOSMutex *mutex) {
ReleaseSRWLockExclusive((PSRWLOCK) mutex); /* error handling? May want to keep counter */
LeaveCriticalSection((CRITICAL_SECTION *) mutex);
} }
void janet_os_rwlock_init(JanetOSRWLock *rwlock) { void janet_os_rwlock_init(JanetOSRWLock *rwlock) {

View File

@@ -589,16 +589,6 @@ JanetAtomicInt janet_atomic_load(JanetAtomicInt volatile *x) {
#endif #endif
} }
JanetAtomicInt janet_atomic_load_relaxed(JanetAtomicInt volatile *x) {
#ifdef _MSC_VER
return _InterlockedOr(x, 0);
#elif defined(JANET_USE_STDATOMIC)
return atomic_load_explicit(x, memory_order_relaxed);
#else
return __atomic_load_n(x, __ATOMIC_RELAXED);
#endif
}
/* Some definitions for function-like macros */ /* Some definitions for function-like macros */
JANET_API JanetStructHead *(janet_struct_head)(JanetStruct st) { JANET_API JanetStructHead *(janet_struct_head)(JanetStruct st) {

View File

@@ -66,7 +66,7 @@ JanetModule janet_native(const char *name, const uint8_t **error) {
JanetBuildConfig modconf = getter(); JanetBuildConfig modconf = getter();
JanetBuildConfig host = janet_config_current(); JanetBuildConfig host = janet_config_current();
if (host.major != modconf.major || if (host.major != modconf.major ||
host.minor != modconf.minor || host.minor < modconf.minor ||
host.bits != modconf.bits) { host.bits != modconf.bits) {
char errbuf[128]; char errbuf[128];
snprintf(errbuf, sizeof(errbuf), "config mismatch - host %d.%.d.%d(%.4x) vs. module %d.%d.%d(%.4x)", snprintf(errbuf, sizeof(errbuf), "config mismatch - host %d.%.d.%d(%.4x) vs. module %d.%d.%d(%.4x)",
@@ -653,15 +653,22 @@ JANET_CORE_FN(janet_core_check_int,
"(int? x)", "(int? x)",
"Check if x can be exactly represented as a 32 bit signed two's complement integer.") { "Check if x can be exactly represented as a 32 bit signed two's complement integer.") {
janet_fixarity(argc, 1); janet_fixarity(argc, 1);
return janet_wrap_boolean(janet_checkint(argv[0])); if (!janet_checktype(argv[0], JANET_NUMBER)) goto ret_false;
double num = janet_unwrap_number(argv[0]);
return janet_wrap_boolean(num == (double)((int32_t)num));
ret_false:
return janet_wrap_false();
} }
JANET_CORE_FN(janet_core_check_nat, JANET_CORE_FN(janet_core_check_nat,
"(nat? x)", "(nat? x)",
"Check if x can be exactly represented as a non-negative 32 bit signed two's complement integer.") { "Check if x can be exactly represented as a non-negative 32 bit signed two's complement integer.") {
janet_fixarity(argc, 1); janet_fixarity(argc, 1);
if (!janet_checkint(argv[0])) return janet_wrap_false(); if (!janet_checktype(argv[0], JANET_NUMBER)) goto ret_false;
return janet_wrap_boolean(janet_unwrap_integer(argv[0]) >= 0); double num = janet_unwrap_number(argv[0]);
return janet_wrap_boolean(num >= 0 && (num == (double)((int32_t)num)));
ret_false:
return janet_wrap_false();
} }
JANET_CORE_FN(janet_core_is_bytes, JANET_CORE_FN(janet_core_is_bytes,

View File

@@ -83,7 +83,7 @@ struct JanetChannel {
int closed; int closed;
int is_threaded; int is_threaded;
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
SRWLOCK lock; CRITICAL_SECTION lock;
#else #else
pthread_mutex_t lock; pthread_mutex_t lock;
#endif #endif
@@ -353,22 +353,21 @@ JanetStream *janet_stream(JanetHandle handle, uint32_t flags, const JanetMethod
static void janet_stream_close_impl(JanetStream *stream) { static void janet_stream_close_impl(JanetStream *stream) {
stream->flags |= JANET_STREAM_CLOSED; stream->flags |= JANET_STREAM_CLOSED;
int canclose = !(stream->flags & JANET_STREAM_NOT_CLOSEABLE);
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
if (stream->handle != INVALID_HANDLE_VALUE) { if (stream->handle != INVALID_HANDLE_VALUE) {
#ifdef JANET_NET #ifdef JANET_NET
if (stream->flags & JANET_STREAM_SOCKET) { if (stream->flags & JANET_STREAM_SOCKET) {
if (canclose) closesocket((SOCKET) stream->handle); closesocket((SOCKET) stream->handle);
} else } else
#endif #endif
{ {
if (canclose) CloseHandle(stream->handle); CloseHandle(stream->handle);
} }
stream->handle = INVALID_HANDLE_VALUE; stream->handle = INVALID_HANDLE_VALUE;
} }
#else #else
if (stream->handle != -1) { if (stream->handle != -1) {
if (canclose) close(stream->handle); close(stream->handle);
stream->handle = -1; stream->handle = -1;
#ifdef JANET_EV_POLL #ifdef JANET_EV_POLL
uint32_t i = stream->index; uint32_t i = stream->index;
@@ -604,44 +603,8 @@ void janet_ev_init_common(void) {
#endif #endif
} }
#ifdef JANET_WINDOWS
static VOID CALLBACK janet_timeout_stop(ULONG_PTR ptr) {
UNREFERENCED_PARAMETER(ptr);
ExitThread(0);
}
#elif JANET_ANDROID
static void janet_timeout_stop(int sig_num) {
if (sig_num == SIGUSR1) {
pthread_exit(0);
}
}
#endif
static void handle_timeout_worker(JanetTimeout to, int cancel) {
if (!to.has_worker) return;
#ifdef JANET_WINDOWS
(void) cancel;
QueueUserAPC(janet_timeout_stop, to.worker, 0);
WaitForSingleObject(to.worker, INFINITE);
CloseHandle(to.worker);
#else
#ifdef JANET_ANDROID
if (cancel) janet_assert(!pthread_kill(to.worker, SIGUSR1), "pthread_kill");
#else
if (cancel) janet_assert(!pthread_cancel(to.worker), "pthread_cancel");
#endif
void *res = NULL;
janet_assert(!pthread_join(to.worker, &res), "pthread_join");
#endif
}
/* Common deinit code */ /* Common deinit code */
void janet_ev_deinit_common(void) { void janet_ev_deinit_common(void) {
JanetTimeout to;
while (peek_timeout(&to)) {
handle_timeout_worker(to, 1);
pop_timeout(0);
}
janet_q_deinit(&janet_vm.spawn); janet_q_deinit(&janet_vm.spawn);
janet_free(janet_vm.tq); janet_free(janet_vm.tq);
janet_table_deinit(&janet_vm.threaded_abstracts); janet_table_deinit(&janet_vm.threaded_abstracts);
@@ -684,6 +647,13 @@ void janet_addtimeout_nil(double sec) {
add_timeout(to); add_timeout(to);
} }
#ifdef JANET_WINDOWS
static VOID CALLBACK janet_timeout_stop(ULONG_PTR ptr) {
UNREFERENCED_PARAMETER(ptr);
ExitThread(0);
}
#endif
static void janet_timeout_cb(JanetEVGenericMessage msg) { static void janet_timeout_cb(JanetEVGenericMessage msg) {
(void) msg; (void) msg;
janet_interpreter_interrupt_handled(&janet_vm); janet_interpreter_interrupt_handled(&janet_vm);
@@ -694,21 +664,15 @@ static DWORD WINAPI janet_timeout_body(LPVOID ptr) {
JanetThreadedTimeout tto = *(JanetThreadedTimeout *)ptr; JanetThreadedTimeout tto = *(JanetThreadedTimeout *)ptr;
janet_free(ptr); janet_free(ptr);
SleepEx((DWORD)(tto.sec * 1000), TRUE); SleepEx((DWORD)(tto.sec * 1000), TRUE);
if (janet_fiber_can_resume(tto.fiber)) {
janet_interpreter_interrupt(tto.vm); janet_interpreter_interrupt(tto.vm);
JanetEVGenericMessage msg = {0}; JanetEVGenericMessage msg = {0};
janet_ev_post_event(tto.vm, janet_timeout_cb, msg); janet_ev_post_event(tto.vm, janet_timeout_cb, msg);
}
return 0; return 0;
} }
#else #else
static void *janet_timeout_body(void *ptr) { static void *janet_timeout_body(void *ptr) {
#ifdef JANET_ANDROID
struct sigaction action;
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
action.sa_handler = &janet_timeout_stop;
sigaction(SIGUSR1, &action, NULL);
#endif
JanetThreadedTimeout tto = *(JanetThreadedTimeout *)ptr; JanetThreadedTimeout tto = *(JanetThreadedTimeout *)ptr;
janet_free(ptr); janet_free(ptr);
struct timespec ts; struct timespec ts;
@@ -717,9 +681,11 @@ static void *janet_timeout_body(void *ptr) {
? (long)((tto.sec - ((uint32_t)tto.sec)) * 1000000000) ? (long)((tto.sec - ((uint32_t)tto.sec)) * 1000000000)
: 0; : 0;
nanosleep(&ts, &ts); nanosleep(&ts, &ts);
if (janet_fiber_can_resume(tto.fiber)) {
janet_interpreter_interrupt(tto.vm); janet_interpreter_interrupt(tto.vm);
JanetEVGenericMessage msg = {0}; JanetEVGenericMessage msg = {0};
janet_ev_post_event(tto.vm, janet_timeout_cb, msg); janet_ev_post_event(tto.vm, janet_timeout_cb, msg);
}
return NULL; return NULL;
} }
#endif #endif
@@ -839,34 +805,6 @@ static int janet_chanat_gc(void *p, size_t s) {
return 0; return 0;
} }
static void janet_chanat_remove_vmref(JanetQueue *fq) {
JanetChannelPending *pending = fq->data;
if (fq->head <= fq->tail) {
for (int32_t i = fq->head; i < fq->tail; i++) {
if (pending[i].thread == &janet_vm) pending[i].thread = NULL;
}
} else {
for (int32_t i = fq->head; i < fq->capacity; i++) {
if (pending[i].thread == &janet_vm) pending[i].thread = NULL;
}
for (int32_t i = 0; i < fq->tail; i++) {
if (pending[i].thread == &janet_vm) pending[i].thread = NULL;
}
}
}
static int janet_chanat_gcperthread(void *p, size_t s) {
(void) s;
JanetChannel *chan = p;
janet_chan_lock(chan);
/* Make sure that the internals of the threaded channel no longer reference _this_ thread. Replace
* those references with NULL. */
janet_chanat_remove_vmref(&chan->read_pending);
janet_chanat_remove_vmref(&chan->write_pending);
janet_chan_unlock(chan);
return 0;
}
static void janet_chanat_mark_fq(JanetQueue *fq) { static void janet_chanat_mark_fq(JanetQueue *fq) {
JanetChannelPending *pending = fq->data; JanetChannelPending *pending = fq->data;
if (fq->head <= fq->tail) { if (fq->head <= fq->tail) {
@@ -949,9 +887,8 @@ static void janet_thread_chan_cb(JanetEVGenericMessage msg) {
int is_read = (mode == JANET_CP_MODE_CHOICE_READ) || (mode == JANET_CP_MODE_READ); int is_read = (mode == JANET_CP_MODE_CHOICE_READ) || (mode == JANET_CP_MODE_READ);
if (is_read) { if (is_read) {
JanetChannelPending reader; JanetChannelPending reader;
while (!janet_q_pop(&channel->read_pending, &reader, sizeof(reader))) { if (!janet_q_pop(&channel->read_pending, &reader, sizeof(reader))) {
JanetVM *vm = reader.thread; JanetVM *vm = reader.thread;
if (!vm) continue;
JanetEVGenericMessage msg; JanetEVGenericMessage msg;
msg.tag = reader.mode; msg.tag = reader.mode;
msg.fiber = reader.fiber; msg.fiber = reader.fiber;
@@ -959,13 +896,11 @@ static void janet_thread_chan_cb(JanetEVGenericMessage msg) {
msg.argp = channel; msg.argp = channel;
msg.argj = x; msg.argj = x;
janet_ev_post_event(vm, janet_thread_chan_cb, msg); janet_ev_post_event(vm, janet_thread_chan_cb, msg);
break;
} }
} else { } else {
JanetChannelPending writer; JanetChannelPending writer;
while (!janet_q_pop(&channel->write_pending, &writer, sizeof(writer))) { if (!janet_q_pop(&channel->write_pending, &writer, sizeof(writer))) {
JanetVM *vm = writer.thread; JanetVM *vm = writer.thread;
if (!vm) continue;
JanetEVGenericMessage msg; JanetEVGenericMessage msg;
msg.tag = writer.mode; msg.tag = writer.mode;
msg.fiber = writer.fiber; msg.fiber = writer.fiber;
@@ -973,7 +908,6 @@ static void janet_thread_chan_cb(JanetEVGenericMessage msg) {
msg.argp = channel; msg.argp = channel;
msg.argj = janet_wrap_nil(); msg.argj = janet_wrap_nil();
janet_ev_post_event(vm, janet_thread_chan_cb, msg); janet_ev_post_event(vm, janet_thread_chan_cb, msg);
break;
} }
} }
} }
@@ -1037,9 +971,7 @@ static int janet_channel_push_with_lock(JanetChannel *channel, Janet x, int mode
msg.argi = (int32_t) reader.sched_id; msg.argi = (int32_t) reader.sched_id;
msg.argp = channel; msg.argp = channel;
msg.argj = x; msg.argj = x;
if (vm) {
janet_ev_post_event(vm, janet_thread_chan_cb, msg); janet_ev_post_event(vm, janet_thread_chan_cb, msg);
}
} else { } else {
if (reader.mode == JANET_CP_MODE_CHOICE_READ) { if (reader.mode == JANET_CP_MODE_CHOICE_READ) {
janet_schedule(reader.fiber, make_read_result(channel, x)); janet_schedule(reader.fiber, make_read_result(channel, x));
@@ -1094,9 +1026,7 @@ static int janet_channel_pop_with_lock(JanetChannel *channel, Janet *item, int i
msg.argi = (int32_t) writer.sched_id; msg.argi = (int32_t) writer.sched_id;
msg.argp = channel; msg.argp = channel;
msg.argj = janet_wrap_nil(); msg.argj = janet_wrap_nil();
if (vm) {
janet_ev_post_event(vm, janet_thread_chan_cb, msg); janet_ev_post_event(vm, janet_thread_chan_cb, msg);
}
} else { } else {
if (writer.mode == JANET_CP_MODE_CHOICE_WRITE) { if (writer.mode == JANET_CP_MODE_CHOICE_WRITE) {
janet_schedule(writer.fiber, make_write_result(channel)); janet_schedule(writer.fiber, make_write_result(channel));
@@ -1360,9 +1290,7 @@ JANET_CORE_FN(cfun_channel_close,
msg.tag = JANET_CP_MODE_CLOSE; msg.tag = JANET_CP_MODE_CLOSE;
msg.argi = (int32_t) writer.sched_id; msg.argi = (int32_t) writer.sched_id;
msg.argj = janet_wrap_nil(); msg.argj = janet_wrap_nil();
if (vm) {
janet_ev_post_event(vm, janet_thread_chan_cb, msg); janet_ev_post_event(vm, janet_thread_chan_cb, msg);
}
} else { } else {
if (janet_fiber_can_resume(writer.fiber)) { if (janet_fiber_can_resume(writer.fiber)) {
if (writer.mode == JANET_CP_MODE_CHOICE_WRITE) { if (writer.mode == JANET_CP_MODE_CHOICE_WRITE) {
@@ -1383,9 +1311,7 @@ JANET_CORE_FN(cfun_channel_close,
msg.tag = JANET_CP_MODE_CLOSE; msg.tag = JANET_CP_MODE_CLOSE;
msg.argi = (int32_t) reader.sched_id; msg.argi = (int32_t) reader.sched_id;
msg.argj = janet_wrap_nil(); msg.argj = janet_wrap_nil();
if (vm) {
janet_ev_post_event(vm, janet_thread_chan_cb, msg); janet_ev_post_event(vm, janet_thread_chan_cb, msg);
}
} else { } else {
if (janet_fiber_can_resume(reader.fiber)) { if (janet_fiber_can_resume(reader.fiber)) {
if (reader.mode == JANET_CP_MODE_CHOICE_READ) { if (reader.mode == JANET_CP_MODE_CHOICE_READ) {
@@ -1478,10 +1404,7 @@ const JanetAbstractType janet_channel_type = {
NULL, /* compare */ NULL, /* compare */
NULL, /* hash */ NULL, /* hash */
janet_chanat_next, janet_chanat_next,
NULL, /* call */ JANET_ATEND_NEXT
NULL, /* length */
NULL, /* bytes */
janet_chanat_gcperthread
}; };
/* Main event loop */ /* Main event loop */
@@ -1514,13 +1437,12 @@ JanetFiber *janet_loop1(void) {
} }
} }
} }
handle_timeout_worker(to, 0);
} }
/* Run scheduled fibers unless interrupts need to be handled. */ /* Run scheduled fibers unless interrupts need to be handled. */
while (janet_vm.spawn.head != janet_vm.spawn.tail) { while (janet_vm.spawn.head != janet_vm.spawn.tail) {
/* Don't run until all interrupts have been marked as handled by calling janet_interpreter_interrupt_handled */ /* Don't run until all interrupts have been marked as handled by calling janet_interpreter_interrupt_handled */
if (janet_atomic_load_relaxed(&janet_vm.auto_suspend)) break; if (janet_vm.auto_suspend) break;
JanetTask task = {NULL, janet_wrap_nil(), JANET_SIGNAL_OK, 0}; JanetTask task = {NULL, janet_wrap_nil(), JANET_SIGNAL_OK, 0};
janet_q_pop(&janet_vm.spawn, &task, sizeof(task)); janet_q_pop(&janet_vm.spawn, &task, sizeof(task));
if (task.fiber->gc.flags & JANET_FIBER_EV_FLAG_SUSPENDED) janet_ev_dec_refcount(); if (task.fiber->gc.flags & JANET_FIBER_EV_FLAG_SUSPENDED) janet_ev_dec_refcount();
@@ -1562,14 +1484,23 @@ JanetFiber *janet_loop1(void) {
while ((has_timeout = peek_timeout(&to))) { while ((has_timeout = peek_timeout(&to))) {
if (to.curr_fiber != NULL) { if (to.curr_fiber != NULL) {
if (!janet_fiber_can_resume(to.curr_fiber)) { if (!janet_fiber_can_resume(to.curr_fiber)) {
pop_timeout(0); if (to.has_worker) {
#ifdef JANET_WINDOWS
QueueUserAPC(janet_timeout_stop, to.worker, 0);
WaitForSingleObject(to.worker, INFINITE);
CloseHandle(to.worker);
#else
pthread_cancel(to.worker);
void *res;
pthread_join(to.worker, &res);
#endif
}
janet_table_remove(&janet_vm.active_tasks, janet_wrap_fiber(to.curr_fiber)); janet_table_remove(&janet_vm.active_tasks, janet_wrap_fiber(to.curr_fiber));
handle_timeout_worker(to, 1); pop_timeout(0);
continue; continue;
} }
} else if (to.fiber->sched_id != to.sched_id) { } else if (to.fiber->sched_id != to.sched_id) {
pop_timeout(0); pop_timeout(0);
handle_timeout_worker(to, 1);
continue; continue;
} }
break; break;
@@ -1734,7 +1665,7 @@ void janet_stream_level_triggered(JanetStream *stream) {
static JanetTimestamp ts_now(void) { static JanetTimestamp ts_now(void) {
struct timespec now; struct timespec now;
janet_assert(-1 != janet_gettime(&now, JANET_TIME_MONOTONIC), "failed to get time"); janet_assert(-1 != clock_gettime(CLOCK_MONOTONIC, &now), "failed to get time");
uint64_t res = 1000 * now.tv_sec; uint64_t res = 1000 * now.tv_sec;
res += now.tv_nsec / 1000000; res += now.tv_nsec / 1000000;
return res; return res;
@@ -1892,7 +1823,7 @@ JanetTimestamp to_interval(const JanetTimestamp ts) {
static JanetTimestamp ts_now(void) { static JanetTimestamp ts_now(void) {
struct timespec now; struct timespec now;
janet_assert(-1 != janet_gettime(&now, JANET_TIME_MONOTONIC), "failed to get time"); janet_assert(-1 != clock_gettime(CLOCK_MONOTONIC, &now), "failed to get time");
uint64_t res = 1000 * now.tv_sec; uint64_t res = 1000 * now.tv_sec;
res += now.tv_nsec / 1000000; res += now.tv_nsec / 1000000;
return res; return res;
@@ -2046,7 +1977,7 @@ void janet_ev_deinit(void) {
static JanetTimestamp ts_now(void) { static JanetTimestamp ts_now(void) {
struct timespec now; struct timespec now;
janet_assert(-1 != janet_gettime(&now, JANET_TIME_MONOTONIC), "failed to get time"); janet_assert(-1 != clock_gettime(CLOCK_REALTIME, &now), "failed to get time");
uint64_t res = 1000 * now.tv_sec; uint64_t res = 1000 * now.tv_sec;
res += now.tv_nsec / 1000000; res += now.tv_nsec / 1000000;
return res; return res;
@@ -2218,7 +2149,7 @@ void janet_ev_post_event(JanetVM *vm, JanetCallback cb, JanetEVGenericMessage ms
event.cb = cb; event.cb = cb;
int fd = vm->selfpipe[1]; int fd = vm->selfpipe[1];
/* handle a bit of back pressure before giving up. */ /* handle a bit of back pressure before giving up. */
int tries = 20; int tries = 4;
while (tries > 0) { while (tries > 0) {
int status; int status;
do { do {
@@ -3065,8 +2996,7 @@ static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) {
uint32_t count1; uint32_t count1;
memcpy(&count1, nextbytes, sizeof(count1)); memcpy(&count1, nextbytes, sizeof(count1));
size_t count = (size_t) count1; size_t count = (size_t) count1;
/* Use division to avoid overflowing size_t */ if (count > (endbytes - nextbytes) * sizeof(JanetCFunRegistry)) {
if (count > (endbytes - nextbytes - sizeof(count1)) / sizeof(JanetCFunRegistry)) {
janet_panic("thread message invalid"); janet_panic("thread message invalid");
} }
janet_vm.registry_count = count; janet_vm.registry_count = count;
@@ -3224,7 +3154,6 @@ JANET_NO_RETURN void janet_sleep_await(double sec) {
to.is_error = 0; to.is_error = 0;
to.sched_id = to.fiber->sched_id; to.sched_id = to.fiber->sched_id;
to.curr_fiber = NULL; to.curr_fiber = NULL;
to.has_worker = 0;
add_timeout(to); add_timeout(to);
janet_await(); janet_await();
} }
@@ -3259,9 +3188,6 @@ JANET_CORE_FN(cfun_ev_deadline,
to.is_error = 0; to.is_error = 0;
to.sched_id = to.fiber->sched_id; to.sched_id = to.fiber->sched_id;
if (use_interrupt) { if (use_interrupt) {
#ifdef JANET_ANDROID
janet_sandbox_assert(JANET_SANDBOX_SIGNAL);
#endif
JanetThreadedTimeout *tto = janet_malloc(sizeof(JanetThreadedTimeout)); JanetThreadedTimeout *tto = janet_malloc(sizeof(JanetThreadedTimeout));
if (NULL == tto) { if (NULL == tto) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
@@ -3579,6 +3505,8 @@ void janet_lib_ev(JanetTable *env) {
janet_register_abstract_type(&janet_channel_type); janet_register_abstract_type(&janet_channel_type);
janet_register_abstract_type(&janet_mutex_type); janet_register_abstract_type(&janet_mutex_type);
janet_register_abstract_type(&janet_rwlock_type); janet_register_abstract_type(&janet_rwlock_type);
janet_lib_filewatch(env);
} }
#endif #endif

View File

@@ -599,33 +599,33 @@ JANET_CORE_FN(cfun_filewatch_make,
JANET_CORE_FN(cfun_filewatch_add, JANET_CORE_FN(cfun_filewatch_add,
"(filewatch/add watcher path &opt flags)", "(filewatch/add watcher path &opt flags)",
"Add a path to the watcher. Available flags depend on the current OS, and are as follows:\n\n" "Add a path to the watcher. Available flags depend on the current OS, and are as follows:\n\n"
"Windows/MINGW (flags correspond to `FILE_NOTIFY_CHANGE_*` flags in win32 documentation):\n\n" "Windows/MINGW (flags correspond to FILE_NOTIFY_CHANGE_* flags in win32 documentation):\n\n"
"* `:all` - trigger an event for all of the below triggers.\n\n" "* `:all` - trigger an event for all of the below triggers.\n\n"
"* `:attributes` - `FILE_NOTIFY_CHANGE_ATTRIBUTES`\n\n" "* `:attributes` - FILE_NOTIFY_CHANGE_ATTRIBUTES\n\n"
"* `:creation` - `FILE_NOTIFY_CHANGE_CREATION`\n\n" "* `:creation` - FILE_NOTIFY_CHANGE_CREATION\n\n"
"* `:dir-name` - `FILE_NOTIFY_CHANGE_DIR_NAME`\n\n" "* `:dir-name` - FILE_NOTIFY_CHANGE_DIR_NAME\n\n"
"* `:last-access` - `FILE_NOTIFY_CHANGE_LAST_ACCESS`\n\n" "* `:last-access` - FILE_NOTIFY_CHANGE_LAST_ACCESS\n\n"
"* `:last-write` - `FILE_NOTIFY_CHANGE_LAST_WRITE`\n\n" "* `:last-write` - FILE_NOTIFY_CHANGE_LAST_WRITE\n\n"
"* `:security` - `FILE_NOTIFY_CHANGE_SECURITY`\n\n" "* `:security` - FILE_NOTIFY_CHANGE_SECURITY\n\n"
"* `:size` - `FILE_NOTIFY_CHANGE_SIZE`\n\n" "* `:size` - FILE_NOTIFY_CHANGE_SIZE\n\n"
"* `:recursive` - watch subdirectories recursively\n\n" "* `:recursive` - watch subdirectories recursively\n\n"
"Linux (flags correspond to `IN_*` flags from <sys/inotify.h>):\n\n" "Linux (flags correspond to IN_* flags from <sys/inotify.h>):\n\n"
"* `:access` - `IN_ACCESS`\n\n" "* `:access` - IN_ACCESS\n\n"
"* `:all` - `IN_ALL_EVENTS`\n\n" "* `:all` - IN_ALL_EVENTS\n\n"
"* `:attrib` - `IN_ATTRIB`\n\n" "* `:attrib` - IN_ATTRIB\n\n"
"* `:close-nowrite` - `IN_CLOSE_NOWRITE`\n\n" "* `:close-nowrite` - IN_CLOSE_NOWRITE\n\n"
"* `:close-write` - `IN_CLOSE_WRITE`\n\n" "* `:close-write` - IN_CLOSE_WRITE\n\n"
"* `:create` - `IN_CREATE`\n\n" "* `:create` - IN_CREATE\n\n"
"* `:delete` - `IN_DELETE`\n\n" "* `:delete` - IN_DELETE\n\n"
"* `:delete-self` - `IN_DELETE_SELF`\n\n" "* `:delete-self` - IN_DELETE_SELF\n\n"
"* `:ignored` - `IN_IGNORED`\n\n" "* `:ignored` - IN_IGNORED\n\n"
"* `:modify` - `IN_MODIFY`\n\n" "* `:modify` - IN_MODIFY\n\n"
"* `:move-self` - `IN_MOVE_SELF`\n\n" "* `:move-self` - IN_MOVE_SELF\n\n"
"* `:moved-from` - `IN_MOVED_FROM`\n\n" "* `:moved-from` - IN_MOVED_FROM\n\n"
"* `:moved-to` - `IN_MOVED_TO`\n\n" "* `:moved-to` - IN_MOVED_TO\n\n"
"* `:open` - `IN_OPEN`\n\n" "* `:open` - IN_OPEN\n\n"
"* `:q-overflow` - `IN_Q_OVERFLOW`\n\n" "* `:q-overflow` - IN_Q_OVERFLOW\n\n"
"* `:unmount` - `IN_UNMOUNT`\n\n\n" "* `:unmount` - IN_UNMOUNT\n\n\n"
"On Windows, events will have the following possible types:\n\n" "On Windows, events will have the following possible types:\n\n"
"* `:unknown`\n\n" "* `:unknown`\n\n"
"* `:added`\n\n" "* `:added`\n\n"
@@ -633,7 +633,7 @@ JANET_CORE_FN(cfun_filewatch_add,
"* `:modified`\n\n" "* `:modified`\n\n"
"* `:renamed-old`\n\n" "* `:renamed-old`\n\n"
"* `:renamed-new`\n\n" "* `:renamed-new`\n\n"
"On Linux, events will have a `:type` corresponding to the possible flags, excluding `:all`.\n" "On Linux, events will a `:type` corresponding to the possible flags, excluding `:all`.\n"
"") { "") {
janet_arity(argc, 2, -1); janet_arity(argc, 2, -1);
JanetWatcher *watcher = janet_getabstract(argv, 0, &janet_filewatch_at); JanetWatcher *watcher = janet_getabstract(argv, 0, &janet_filewatch_at);

View File

@@ -346,9 +346,6 @@ static void janet_deinit_block(JanetGCObject *mem) {
break; break;
case JANET_MEMORY_ABSTRACT: { case JANET_MEMORY_ABSTRACT: {
JanetAbstractHead *head = (JanetAbstractHead *)mem; JanetAbstractHead *head = (JanetAbstractHead *)mem;
if (head->type->gcperthread) {
janet_assert(!head->type->gcperthread(head->data, head->size), "per-thread finalizer failed");
}
if (head->type->gc) { if (head->type->gc) {
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed"); janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
} }
@@ -500,12 +497,9 @@ void janet_sweep() {
/* If not visited... */ /* If not visited... */
if (!janet_truthy(items[i].value)) { if (!janet_truthy(items[i].value)) {
void *abst = janet_unwrap_abstract(items[i].key); void *abst = janet_unwrap_abstract(items[i].key);
JanetAbstractHead *head = janet_abstract_head(abst);
if (head->type->gcperthread) {
janet_assert(!head->type->gcperthread(head->data, head->size), "per-thread finalizer failed");
}
if (0 == janet_abstract_decref(abst)) { if (0 == janet_abstract_decref(abst)) {
/* Run finalizer */ /* Run finalizer */
JanetAbstractHead *head = janet_abstract_head(abst);
if (head->type->gc) { if (head->type->gc) {
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed"); janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
} }
@@ -678,11 +672,8 @@ void janet_clear_memory(void) {
for (int32_t i = 0; i < janet_vm.threaded_abstracts.capacity; i++) { for (int32_t i = 0; i < janet_vm.threaded_abstracts.capacity; i++) {
if (janet_checktype(items[i].key, JANET_ABSTRACT)) { if (janet_checktype(items[i].key, JANET_ABSTRACT)) {
void *abst = janet_unwrap_abstract(items[i].key); void *abst = janet_unwrap_abstract(items[i].key);
JanetAbstractHead *head = janet_abstract_head(abst);
if (head->type->gcperthread) {
janet_assert(!head->type->gcperthread(head->data, head->size), "per-thread finalizer failed");
}
if (0 == janet_abstract_decref(abst)) { if (0 == janet_abstract_decref(abst)) {
JanetAbstractHead *head = janet_abstract_head(abst);
if (head->type->gc) { if (head->type->gc) {
janet_assert(!head->type->gc(head->data, head->size), "finalizer failed"); janet_assert(!head->type->gc(head->data, head->size), "finalizer failed");
} }

View File

@@ -341,7 +341,7 @@ static int janet_get_sockettype(Janet *argv, int32_t argc, int32_t n) {
/* Needs argc >= offset + 2 */ /* Needs argc >= offset + 2 */
/* For unix paths, just rertuns a single sockaddr and sets *is_unix to 1, /* For unix paths, just rertuns a single sockaddr and sets *is_unix to 1,
* otherwise 0. Also, ignores is_bind when is a unix socket. */ * otherwise 0. Also, ignores is_bind when is a unix socket. */
static struct addrinfo *janet_get_addrinfo(Janet *argv, int32_t offset, int socktype, int passive, int *is_unix, socklen_t *sizeout) { static struct addrinfo *janet_get_addrinfo(Janet *argv, int32_t offset, int socktype, int passive, int *is_unix) {
/* Unix socket support - not yet supported on windows. */ /* Unix socket support - not yet supported on windows. */
#ifndef JANET_WINDOWS #ifndef JANET_WINDOWS
if (janet_keyeq(argv[offset], "unix")) { if (janet_keyeq(argv[offset], "unix")) {
@@ -352,14 +352,15 @@ static struct addrinfo *janet_get_addrinfo(Janet *argv, int32_t offset, int sock
} }
saddr->sun_family = AF_UNIX; saddr->sun_family = AF_UNIX;
size_t path_size = sizeof(saddr->sun_path); size_t path_size = sizeof(saddr->sun_path);
snprintf(saddr->sun_path, path_size, "%s", path);
*sizeout = sizeof(struct sockaddr_un);
#ifdef JANET_LINUX #ifdef JANET_LINUX
if (path[0] == '@') { if (path[0] == '@') {
saddr->sun_path[0] = '\0'; saddr->sun_path[0] = '\0';
*sizeout = offsetof(struct sockaddr_un, sun_path) + janet_string_length(path); snprintf(saddr->sun_path + 1, path_size - 1, "%s", path + 1);
} } else
#endif #endif
{
snprintf(saddr->sun_path, path_size, "%s", path);
}
*is_unix = 1; *is_unix = 1;
return (struct addrinfo *) saddr; return (struct addrinfo *) saddr;
} }
@@ -384,11 +385,6 @@ static struct addrinfo *janet_get_addrinfo(Janet *argv, int32_t offset, int sock
janet_panicf("could not get address info: %s", gai_strerror(status)); janet_panicf("could not get address info: %s", gai_strerror(status));
} }
*is_unix = 0; *is_unix = 0;
#ifdef JANET_WINDOWS
*sizeout = 0;
#else
*sizeout = sizeof(struct sockaddr_un);
#endif
return ai; return ai;
} }
@@ -409,13 +405,12 @@ JANET_CORE_FN(cfun_net_sockaddr,
int socktype = janet_get_sockettype(argv, argc, 2); int socktype = janet_get_sockettype(argv, argc, 2);
int is_unix = 0; int is_unix = 0;
int make_arr = (argc >= 3 && janet_truthy(argv[3])); int make_arr = (argc >= 3 && janet_truthy(argv[3]));
socklen_t addrsize = 0; struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 0, &is_unix);
struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 0, &is_unix, &addrsize);
#ifndef JANET_WINDOWS #ifndef JANET_WINDOWS
/* no unix domain socket support on windows yet */ /* no unix domain socket support on windows yet */
if (is_unix) { if (is_unix) {
void *abst = janet_abstract(&janet_address_type, addrsize); void *abst = janet_abstract(&janet_address_type, sizeof(struct sockaddr_un));
memcpy(abst, ai, addrsize); memcpy(abst, ai, sizeof(struct sockaddr_un));
Janet ret = janet_wrap_abstract(abst); Janet ret = janet_wrap_abstract(abst);
return make_arr ? janet_wrap_array(janet_array_n(&ret, 1)) : ret; return make_arr ? janet_wrap_array(janet_array_n(&ret, 1)) : ret;
} }
@@ -466,8 +461,7 @@ JANET_CORE_FN(cfun_net_connect,
} }
/* Where we're connecting to */ /* Where we're connecting to */
socklen_t addrlen = 0; struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 0, &is_unix);
struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 0, &is_unix, &addrlen);
/* Check if we're binding address */ /* Check if we're binding address */
struct addrinfo *binding = NULL; struct addrinfo *binding = NULL;
@@ -492,6 +486,7 @@ JANET_CORE_FN(cfun_net_connect,
/* Create socket */ /* Create socket */
JSock sock = JSOCKDEFAULT; JSock sock = JSOCKDEFAULT;
void *addr = NULL; void *addr = NULL;
socklen_t addrlen = 0;
#ifndef JANET_WINDOWS #ifndef JANET_WINDOWS
if (is_unix) { if (is_unix) {
sock = socket(AF_UNIX, socktype | JSOCKFLAGS, 0); sock = socket(AF_UNIX, socktype | JSOCKFLAGS, 0);
@@ -501,6 +496,7 @@ JANET_CORE_FN(cfun_net_connect,
janet_panicf("could not create socket: %V", v); janet_panicf("could not create socket: %V", v);
} }
addr = (void *) ai; addr = (void *) ai;
addrlen = sizeof(struct sockaddr_un);
} else } else
#endif #endif
{ {
@@ -547,9 +543,7 @@ JANET_CORE_FN(cfun_net_connect,
} }
/* Wrap socket in abstract type JanetStream */ /* Wrap socket in abstract type JanetStream */
uint32_t udp_flag = 0; JanetStream *stream = make_stream(sock, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
if (socktype == SOCK_DGRAM) udp_flag = JANET_STREAM_UDPSERVER;
JanetStream *stream = make_stream(sock, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE | udp_flag);
/* Set up the socket for non-blocking IO before connecting */ /* Set up the socket for non-blocking IO before connecting */
janet_net_socknoblock(sock); janet_net_socknoblock(sock);
@@ -587,56 +581,6 @@ JANET_CORE_FN(cfun_net_connect,
net_sched_connect(stream); net_sched_connect(stream);
} }
JANET_CORE_FN(cfun_net_socket,
"(net/socket &opt type)",
"Creates a new unbound socket. Type is an optional keyword, "
"either a :stream (usually tcp), or :datagram (usually udp). The default is :stream.") {
janet_arity(argc, 0, 1);
int socktype = janet_get_sockettype(argv, argc, 0);
/* Create socket */
JSock sfd = JSOCKDEFAULT;
struct addrinfo *ai = NULL;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = socktype;
hints.ai_flags = 0;
int status = getaddrinfo(NULL, "0", &hints, &ai);
if (status) {
janet_panicf("could not get address info: %s", gai_strerror(status));
}
struct addrinfo *rp = NULL;
for (rp = ai; rp != NULL; rp = rp->ai_next) {
#ifdef JANET_WINDOWS
sfd = WSASocketW(rp->ai_family, rp->ai_socktype | JSOCKFLAGS, rp->ai_protocol, NULL, 0, WSA_FLAG_OVERLAPPED);
#else
sfd = socket(rp->ai_family, rp->ai_socktype | JSOCKFLAGS, rp->ai_protocol);
#endif
if (JSOCKVALID(sfd)) {
break;
}
}
freeaddrinfo(ai);
if (!JSOCKVALID(sfd)) {
Janet v = janet_ev_lasterr();
janet_panicf("could not create socket: %V", v);
}
/* Wrap socket in abstract type JanetStream */
uint32_t udp_flag = 0;
if (socktype == SOCK_DGRAM) udp_flag = JANET_STREAM_UDPSERVER;
JanetStream *stream = make_stream(sfd, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE | udp_flag);
/* Set up the socket for non-blocking IO */
janet_net_socknoblock(sfd);
return janet_wrap_abstract(stream);
}
static const char *serverify_socket(JSock sfd, int reuse_addr, int reuse_port) { static const char *serverify_socket(JSock sfd, int reuse_addr, int reuse_port) {
/* Set various socket options */ /* Set various socket options */
int enable = 1; int enable = 1;
@@ -713,15 +657,14 @@ JANET_CORE_FN(cfun_net_listen,
"The type parameter specifies the type of network connection, either " "The type parameter specifies the type of network connection, either "
"a :stream (usually tcp), or :datagram (usually udp). If not specified, the default is " "a :stream (usually tcp), or :datagram (usually udp). If not specified, the default is "
":stream. The host and port arguments are the same as in net/address. The last boolean parameter `no-reuse` will " ":stream. The host and port arguments are the same as in net/address. The last boolean parameter `no-reuse` will "
"disable the use of `SO_REUSEADDR` and `SO_REUSEPORT` when creating a server on some operating systems.") { "disable the use of SO_REUSEADDR and SO_REUSEPORT when creating a server on some operating systems.") {
janet_sandbox_assert(JANET_SANDBOX_NET_LISTEN); janet_sandbox_assert(JANET_SANDBOX_NET_LISTEN);
janet_arity(argc, 2, 4); janet_arity(argc, 2, 4);
/* Get host, port, and handler*/ /* Get host, port, and handler*/
int socktype = janet_get_sockettype(argv, argc, 2); int socktype = janet_get_sockettype(argv, argc, 2);
int is_unix = 0; int is_unix = 0;
socklen_t addrlen = 0; struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 1, &is_unix);
struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 1, &is_unix, &addrlen);
int reuse = !(argc >= 4 && janet_truthy(argv[3])); int reuse = !(argc >= 4 && janet_truthy(argv[3]));
JSock sfd = JSOCKDEFAULT; JSock sfd = JSOCKDEFAULT;
@@ -733,7 +676,7 @@ JANET_CORE_FN(cfun_net_listen,
janet_panicf("could not create socket: %V", janet_ev_lasterr()); janet_panicf("could not create socket: %V", janet_ev_lasterr());
} }
const char *err = serverify_socket(sfd, reuse, 0); const char *err = serverify_socket(sfd, reuse, 0);
if (NULL != err || bind(sfd, (struct sockaddr *)ai, addrlen)) { if (NULL != err || bind(sfd, (struct sockaddr *)ai, sizeof(struct sockaddr_un))) {
JSOCKCLOSE(sfd); JSOCKCLOSE(sfd);
janet_free(ai); janet_free(ai);
if (err) { if (err) {
@@ -1135,7 +1078,6 @@ void janet_lib_net(JanetTable *env) {
JanetRegExt net_cfuns[] = { JanetRegExt net_cfuns[] = {
JANET_CORE_REG("net/address", cfun_net_sockaddr), JANET_CORE_REG("net/address", cfun_net_sockaddr),
JANET_CORE_REG("net/listen", cfun_net_listen), JANET_CORE_REG("net/listen", cfun_net_listen),
JANET_CORE_REG("net/socket", cfun_net_socket),
JANET_CORE_REG("net/accept", cfun_stream_accept), JANET_CORE_REG("net/accept", cfun_stream_accept),
JANET_CORE_REG("net/accept-loop", cfun_stream_accept_loop), JANET_CORE_REG("net/accept-loop", cfun_stream_accept_loop),
JANET_CORE_REG("net/read", cfun_stream_read), JANET_CORE_REG("net/read", cfun_stream_read),

View File

@@ -66,7 +66,6 @@
#ifdef JANET_APPLE #ifdef JANET_APPLE
#include <crt_externs.h> #include <crt_externs.h>
#define environ (*_NSGetEnviron()) #define environ (*_NSGetEnviron())
#include <AvailabilityMacros.h>
#else #else
extern char **environ; extern char **environ;
#endif #endif
@@ -82,14 +81,8 @@ extern char **environ;
#ifndef JANET_SPAWN_NO_CHDIR #ifndef JANET_SPAWN_NO_CHDIR
#ifdef __GLIBC__ #ifdef __GLIBC__
#define JANET_SPAWN_CHDIR #define JANET_SPAWN_CHDIR
#elif defined(JANET_APPLE) #elif defined(JANET_APPLE) /* Some older versions may not work here. */
/* The posix_spawn_file_actions_addchdir_np function
* has only been implemented since macOS 10.15 */
#if defined(MAC_OS_X_VERSION_10_15) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_15)
#define JANET_SPAWN_CHDIR #define JANET_SPAWN_CHDIR
#else
#define JANET_SPAWN_NO_CHDIR
#endif
#elif defined(__FreeBSD__) /* Not all BSDs work, for example openBSD doesn't seem to support this */ #elif defined(__FreeBSD__) /* Not all BSDs work, for example openBSD doesn't seem to support this */
#define JANET_SPAWN_CHDIR #define JANET_SPAWN_CHDIR
#endif #endif
@@ -180,8 +173,6 @@ JANET_CORE_FN(os_which,
return janet_ckeywordv("dragonfly"); return janet_ckeywordv("dragonfly");
#elif defined(JANET_BSD) #elif defined(JANET_BSD)
return janet_ckeywordv("bsd"); return janet_ckeywordv("bsd");
#elif defined(JANET_ILLUMOS)
return janet_ckeywordv("illumos");
#else #else
return janet_ckeywordv("posix"); return janet_ckeywordv("posix");
#endif #endif
@@ -321,13 +312,6 @@ JANET_CORE_FN(os_cpu_count,
return dflt; return dflt;
} }
return janet_wrap_integer(result); return janet_wrap_integer(result);
#elif defined(JANET_ILLUMOS)
(void) dflt;
long result = sysconf(_SC_NPROCESSORS_CONF);
if (result < 0) {
return dflt;
}
return janet_wrap_integer(result);
#else #else
return dflt; return dflt;
#endif #endif
@@ -1270,7 +1254,7 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) {
} else if (new_in != JANET_HANDLE_NONE) { } else if (new_in != JANET_HANDLE_NONE) {
startupInfo.hStdInput = new_in; startupInfo.hStdInput = new_in;
} else { } else {
startupInfo.hStdInput = (HANDLE) _get_osfhandle(_fileno(stdin)); startupInfo.hStdInput = (HANDLE) _get_osfhandle(0);
} }
if (pipe_out != JANET_HANDLE_NONE) { if (pipe_out != JANET_HANDLE_NONE) {
@@ -1278,7 +1262,7 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) {
} else if (new_out != JANET_HANDLE_NONE) { } else if (new_out != JANET_HANDLE_NONE) {
startupInfo.hStdOutput = new_out; startupInfo.hStdOutput = new_out;
} else { } else {
startupInfo.hStdOutput = (HANDLE) _get_osfhandle(_fileno(stdout)); startupInfo.hStdOutput = (HANDLE) _get_osfhandle(1);
} }
if (pipe_err != JANET_HANDLE_NONE) { if (pipe_err != JANET_HANDLE_NONE) {
@@ -1288,7 +1272,7 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) {
} else if (stderr_is_stdout) { } else if (stderr_is_stdout) {
startupInfo.hStdError = startupInfo.hStdOutput; startupInfo.hStdError = startupInfo.hStdOutput;
} else { } else {
startupInfo.hStdError = (HANDLE) _get_osfhandle(_fileno(stderr)); startupInfo.hStdError = (HANDLE) _get_osfhandle(2);
} }
int cp_failed = 0; int cp_failed = 0;
@@ -2879,9 +2863,6 @@ void janet_lib_os(JanetTable *env) {
JANET_CORE_REG("os/proc-kill", os_proc_kill), JANET_CORE_REG("os/proc-kill", os_proc_kill),
JANET_CORE_REG("os/proc-close", os_proc_close), JANET_CORE_REG("os/proc-close", os_proc_close),
JANET_CORE_REG("os/getpid", os_proc_getpid), JANET_CORE_REG("os/getpid", os_proc_getpid),
#ifdef JANET_EV
JANET_CORE_REG("os/sigaction", os_sigaction),
#endif
#endif #endif
/* high resolution timers */ /* high resolution timers */
@@ -2890,6 +2871,7 @@ void janet_lib_os(JanetTable *env) {
#ifdef JANET_EV #ifdef JANET_EV
JANET_CORE_REG("os/open", os_open), /* fs read and write */ JANET_CORE_REG("os/open", os_open), /* fs read and write */
JANET_CORE_REG("os/pipe", os_pipe), JANET_CORE_REG("os/pipe", os_pipe),
JANET_CORE_REG("os/sigaction", os_sigaction),
#endif #endif
#endif #endif
JANET_REG_END JANET_REG_END

View File

@@ -1060,12 +1060,20 @@ void janet_buffer_format(
break; break;
} }
case 's': { case 's': {
const char *s = janet_getcbytes(argv, arg); JanetByteView bytes = janet_getbytes(argv, arg);
const uint8_t *s = bytes.bytes;
int32_t l = bytes.len;
if (form[2] == '\0') if (form[2] == '\0')
janet_buffer_push_cstring(b, s); janet_buffer_push_bytes(b, s, l);
else { else {
if (l != (int32_t) strlen((const char *) s))
janet_panic("string contains zeros");
if (!strchr(form, '.') && l >= 100) {
janet_panic("no precision and string is too long to be formatted");
} else {
nb = snprintf(item, MAX_ITEM, form, s); nb = snprintf(item, MAX_ITEM, form, s);
} }
}
break; break;
} }
case 'V': { case 'V': {

View File

@@ -26,8 +26,7 @@
#include "state.h" #include "state.h"
#endif #endif
/* Run a string of code. The return value is a set of error flags, JANET_DO_ERROR_RUNTIME, JANET_DO_ERROR_COMPILE, and JANET_DOR_ERROR_PARSE if /* Run a string */
* any errors were encountered in those phases. More information is printed to stderr. */
int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out) { int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out) {
JanetParser *parser; JanetParser *parser;
int errflags = 0, done = 0; int errflags = 0, done = 0;
@@ -56,7 +55,7 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
JanetSignal status = janet_continue(fiber, janet_wrap_nil(), &ret); JanetSignal status = janet_continue(fiber, janet_wrap_nil(), &ret);
if (status != JANET_SIGNAL_OK && status != JANET_SIGNAL_EVENT) { if (status != JANET_SIGNAL_OK && status != JANET_SIGNAL_EVENT) {
janet_stacktrace_ext(fiber, ret, ""); janet_stacktrace_ext(fiber, ret, "");
errflags |= JANET_DO_ERROR_RUNTIME; errflags |= 0x01;
done = 1; done = 1;
} }
} else { } else {
@@ -76,7 +75,7 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
janet_eprintf("%s:%d:%d: compile error: %s\n", sourcePath, janet_eprintf("%s:%d:%d: compile error: %s\n", sourcePath,
line, col, (const char *)cres.error); line, col, (const char *)cres.error);
} }
errflags |= JANET_DO_ERROR_COMPILE; errflags |= 0x02;
done = 1; done = 1;
} }
} }
@@ -90,7 +89,7 @@ int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char
break; break;
case JANET_PARSE_ERROR: { case JANET_PARSE_ERROR: {
const char *e = janet_parser_error(parser); const char *e = janet_parser_error(parser);
errflags |= JANET_DO_ERROR_PARSE; errflags |= 0x04;
ret = janet_cstringv(e); ret = janet_cstringv(e);
int32_t line = (int32_t) parser->line; int32_t line = (int32_t) parser->line;
int32_t col = (int32_t) parser->column; int32_t col = (int32_t) parser->column;

View File

@@ -23,11 +23,8 @@
#ifndef JANET_STATE_H_defined #ifndef JANET_STATE_H_defined
#define JANET_STATE_H_defined #define JANET_STATE_H_defined
#ifndef JANET_AMALG
#include "features.h"
#include <janet.h> #include <janet.h>
#include <stdint.h> #include <stdint.h>
#endif
#ifdef JANET_EV #ifdef JANET_EV
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS

View File

@@ -931,24 +931,27 @@ int janet_gettime(struct timespec *spec, enum JanetTimeSource source) {
#include <mach/clock.h> #include <mach/clock.h>
#include <mach/mach.h> #include <mach/mach.h>
int janet_gettime(struct timespec *spec, enum JanetTimeSource source) { int janet_gettime(struct timespec *spec, enum JanetTimeSource source) {
if (source == JANET_TIME_CPUTIME) { if (source == JANET_TIME_REALTIME) {
clock_t tmp = clock();
spec->tv_sec = tmp / CLOCKS_PER_SEC;
spec->tv_nsec = ((tmp - (spec->tv_sec * CLOCKS_PER_SEC)) * 1000000000) / CLOCKS_PER_SEC;
} else {
clock_serv_t cclock; clock_serv_t cclock;
mach_timespec_t mts; mach_timespec_t mts;
clock_id_t cid = CALENDAR_CLOCK; host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
if (source == JANET_TIME_REALTIME) {
cid = CALENDAR_CLOCK;
} else if (source == JANET_TIME_MONOTONIC) {
cid = SYSTEM_CLOCK;
}
host_get_clock_service(mach_host_self(), cid, &cclock);
clock_get_time(cclock, &mts); clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock); mach_port_deallocate(mach_task_self(), cclock);
spec->tv_sec = mts.tv_sec; spec->tv_sec = mts.tv_sec;
spec->tv_nsec = mts.tv_nsec; spec->tv_nsec = mts.tv_nsec;
} else if (source == JANET_TIME_MONOTONIC) {
clock_serv_t cclock;
int nsecs;
mach_msg_type_number_t count;
host_get_clock_service(mach_host_self(), clock, &cclock);
clock_get_attributes(cclock, CLOCK_GET_TIME_RES, (clock_attr_t)&nsecs, &count);
mach_port_deallocate(mach_task_self(), cclock);
clock_getres(CLOCK_MONOTONIC, spec);
}
if (source == JANET_TIME_CPUTIME) {
clock_t tmp = clock();
spec->tv_sec = tmp;
spec->tv_nsec = (tmp - spec->tv_sec) * 1.0e9;
} }
return 0; return 0;
} }

View File

@@ -115,7 +115,7 @@
#define vm_maybe_auto_suspend(COND) #define vm_maybe_auto_suspend(COND)
#else #else
#define vm_maybe_auto_suspend(COND) do { \ #define vm_maybe_auto_suspend(COND) do { \
if ((COND) && janet_atomic_load_relaxed(&janet_vm.auto_suspend)) { \ if ((COND) && janet_vm.auto_suspend) { \
fiber->flags |= (JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP); \ fiber->flags |= (JANET_FIBER_RESUME_NO_USEVAL | JANET_FIBER_RESUME_NO_SKIP); \
vm_return(JANET_SIGNAL_INTERRUPT, janet_wrap_nil()); \ vm_return(JANET_SIGNAL_INTERRUPT, janet_wrap_nil()); \
} \ } \

View File

@@ -67,21 +67,11 @@ extern "C" {
#define JANET_LINUX 1 #define JANET_LINUX 1
#endif #endif
/* Check for Android */
#ifdef __ANDROID__
#define JANET_ANDROID 1
#endif
/* Check for Cygwin */ /* Check for Cygwin */
#if defined(__CYGWIN__) #if defined(__CYGWIN__)
#define JANET_CYGWIN 1 #define JANET_CYGWIN 1
#endif #endif
/* Check for Illumos */
#if defined(__illumos__)
#define JANET_ILLUMOS 1
#endif
/* Check Unix */ /* Check Unix */
#if defined(_AIX) \ #if defined(_AIX) \
|| defined(__APPLE__) /* Darwin */ \ || defined(__APPLE__) /* Darwin */ \
@@ -167,7 +157,7 @@ extern "C" {
#endif #endif
/* Check sun */ /* Check sun */
#if defined(__sun) && !defined(JANET_ILLUMOS) #ifdef __sun
#define JANET_NO_UTC_MKTIME #define JANET_NO_UTC_MKTIME
#endif #endif
@@ -175,12 +165,14 @@ extern "C" {
/* Also enable the thread library only if not single-threaded */ /* Also enable the thread library only if not single-threaded */
#ifdef JANET_SINGLE_THREADED #ifdef JANET_SINGLE_THREADED
#define JANET_THREAD_LOCAL #define JANET_THREAD_LOCAL
#elif !(defined(JANET_THREAD_LOCAL)) && defined(__GNUC__) #undef JANET_THREADS
#elif defined(__GNUC__)
#define JANET_THREAD_LOCAL __thread #define JANET_THREAD_LOCAL __thread
#elif !(defined(JANET_THREAD_LOCAL)) && defined(_MSC_BUILD) #elif defined(_MSC_BUILD)
#define JANET_THREAD_LOCAL __declspec(thread) #define JANET_THREAD_LOCAL __declspec(thread)
#elif !(defined(JANET_THREAD_LOCAL)) #else
#define JANET_THREAD_LOCAL #define JANET_THREAD_LOCAL
#undef JANET_THREADS
#endif #endif
/* Enable or disable dynamic module loading. Enabled by default. */ /* Enable or disable dynamic module loading. Enabled by default. */
@@ -599,7 +591,6 @@ typedef void *JanetAbstract;
#define JANET_STREAM_WRITABLE 0x400 #define JANET_STREAM_WRITABLE 0x400
#define JANET_STREAM_ACCEPTABLE 0x800 #define JANET_STREAM_ACCEPTABLE 0x800
#define JANET_STREAM_UDPSERVER 0x1000 #define JANET_STREAM_UDPSERVER 0x1000
#define JANET_STREAM_NOT_CLOSEABLE 0x2000
#define JANET_STREAM_TOCLOSE 0x10000 #define JANET_STREAM_TOCLOSE 0x10000
typedef enum { typedef enum {
@@ -672,7 +663,6 @@ typedef int32_t JanetAtomicInt;
JANET_API JanetAtomicInt janet_atomic_inc(JanetAtomicInt volatile *x); JANET_API JanetAtomicInt janet_atomic_inc(JanetAtomicInt volatile *x);
JANET_API JanetAtomicInt janet_atomic_dec(JanetAtomicInt volatile *x); JANET_API JanetAtomicInt janet_atomic_dec(JanetAtomicInt volatile *x);
JANET_API JanetAtomicInt janet_atomic_load(JanetAtomicInt volatile *x); JANET_API JanetAtomicInt janet_atomic_load(JanetAtomicInt volatile *x);
JANET_API JanetAtomicInt janet_atomic_load_relaxed(JanetAtomicInt volatile *x);
/* We provide three possible implementations of Janets. The preferred /* We provide three possible implementations of Janets. The preferred
* nanboxing approach, for 32 or 64 bits, and the standard C version. Code in the rest of the * nanboxing approach, for 32 or 64 bits, and the standard C version. Code in the rest of the
@@ -1188,7 +1178,6 @@ struct JanetAbstractType {
Janet(*call)(void *p, int32_t argc, Janet *argv); Janet(*call)(void *p, int32_t argc, Janet *argv);
size_t (*length)(void *p, size_t len); size_t (*length)(void *p, size_t len);
JanetByteView(*bytes)(void *p, size_t len); JanetByteView(*bytes)(void *p, size_t len);
int (*gcperthread)(void *data, size_t len);
}; };
/* Some macros to let us add extra types to JanetAbstract types without /* Some macros to let us add extra types to JanetAbstract types without
@@ -1208,8 +1197,7 @@ struct JanetAbstractType {
#define JANET_ATEND_NEXT NULL,JANET_ATEND_CALL #define JANET_ATEND_NEXT NULL,JANET_ATEND_CALL
#define JANET_ATEND_CALL NULL,JANET_ATEND_LENGTH #define JANET_ATEND_CALL NULL,JANET_ATEND_LENGTH
#define JANET_ATEND_LENGTH NULL,JANET_ATEND_BYTES #define JANET_ATEND_LENGTH NULL,JANET_ATEND_BYTES
#define JANET_ATEND_BYTES NULL,JANET_ATEND_GCPERTHREAD #define JANET_ATEND_BYTES
#define JANET_ATEND_GCPERTHREAD
struct JanetReg { struct JanetReg {
const char *name; const char *name;
@@ -1467,10 +1455,10 @@ JANET_API int32_t janet_abstract_incref(void *abst);
JANET_API int32_t janet_abstract_decref(void *abst); JANET_API int32_t janet_abstract_decref(void *abst);
/* Expose channel utilities */ /* Expose channel utilities */
JANET_API JanetChannel *janet_channel_make(uint32_t limit); JanetChannel *janet_channel_make(uint32_t limit);
JANET_API JanetChannel *janet_channel_make_threaded(uint32_t limit); JanetChannel *janet_channel_make_threaded(uint32_t limit);
JANET_API JanetChannel *janet_getchannel(const Janet *argv, int32_t n); JanetChannel *janet_getchannel(const Janet *argv, int32_t n);
JANET_API JanetChannel *janet_optchannel(const Janet *argv, int32_t argc, int32_t n, JanetChannel *dflt); JanetChannel *janet_optchannel(const Janet *argv, int32_t argc, int32_t n, JanetChannel *dflt);
JANET_API int janet_channel_give(JanetChannel *channel, Janet x); JANET_API int janet_channel_give(JanetChannel *channel, Janet x);
JANET_API int janet_channel_take(JanetChannel *channel, Janet *out); JANET_API int janet_channel_take(JanetChannel *channel, Janet *out);
@@ -1618,9 +1606,6 @@ JANET_API JanetTable *janet_core_env(JanetTable *replacements);
JANET_API JanetTable *janet_core_lookup_table(JanetTable *replacements); JANET_API JanetTable *janet_core_lookup_table(JanetTable *replacements);
/* Execute strings */ /* Execute strings */
#define JANET_DO_ERROR_RUNTIME 0x01
#define JANET_DO_ERROR_COMPILE 0x02
#define JANET_DO_ERROR_PARSE 0x04
JANET_API int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out); JANET_API int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out);
JANET_API int janet_dostring(JanetTable *env, const char *str, const char *sourcePath, Janet *out); JANET_API int janet_dostring(JanetTable *env, const char *str, const char *sourcePath, Janet *out);

View File

@@ -865,13 +865,6 @@
(assert (deep= ~(,import* "a" :as "b" :fresh maybe) (assert (deep= ~(,import* "a" :as "b" :fresh maybe)
(macex '(import a :as b :fresh maybe))) "import macro 2") (macex '(import a :as b :fresh maybe))) "import macro 2")
# 2af3f21d
(assert-error "import macro 2" (macex '(import a :fresh)))
(assert-error "import macro 3" (macex '(import a :as b :fresh)))
(assert-error "import macro 4" (macex '(import b "notakeyword" value)))
(assert (deep= ~(,import* "a" :fresh nil)
(macex '(import a :fresh nil))) "import macro 5")
# #477 walk preserving bracket type # #477 walk preserving bracket type
# 0a1d902f4 # 0a1d902f4
(assert (= :brackets (tuple/type (postwalk identity '[]))) (assert (= :brackets (tuple/type (postwalk identity '[])))

View File

@@ -106,8 +106,6 @@
(calc-2 "(+ 9 10 11 12)")) (calc-2 "(+ 9 10 11 12)"))
@[10 26 42]) "parallel subprocesses 2") @[10 26 42]) "parallel subprocesses 2")
# (print "file piping")
# File piping # File piping
# a1cc5ca04 # a1cc5ca04
(assert-no-error "file writing 1" (assert-no-error "file writing 1"
@@ -227,8 +225,6 @@
(++ iterations) (++ iterations)
(ev/write stream " "))) (ev/write stream " ")))
# (print "local name / peer name testing")
# Test localname and peername # Test localname and peername
# 077bf5eba # 077bf5eba
(repeat 10 (repeat 10
@@ -411,8 +407,6 @@
(while (def msg (ev/read connection 100)) (while (def msg (ev/read connection 100))
(broadcast name (string msg))))))) (broadcast name (string msg)))))))
# (print "chat app testing")
# Now launch the chat server # Now launch the chat server
(def chat-server (net/listen test-host test-port)) (def chat-server (net/listen test-host test-port))
(ev/spawn (ev/spawn
@@ -506,8 +500,6 @@
(let [s (net/listen :unix uds-path :stream)] (let [s (net/listen :unix uds-path :stream)]
(:close s)))))) (:close s))))))
# (print "accept loop testing")
# net/accept-loop level triggering # net/accept-loop level triggering
(gccollect) (gccollect)
(def maxconn 50) (def maxconn 50)
@@ -530,8 +522,6 @@
(assert (= maxconn connect-count)) (assert (= maxconn connect-count))
(:close s) (:close s)
# (print "running deadline tests...")
# Cancel os/proc-wait with ev/deadline # Cancel os/proc-wait with ev/deadline
(let [p (os/spawn [;run janet "-e" "(os/sleep 4)"] :p)] (let [p (os/spawn [;run janet "-e" "(os/sleep 4)"] :p)]
(var terminated-normally false) (var terminated-normally false)
@@ -556,35 +546,9 @@
(ev/sleep 0.15) (ev/sleep 0.15)
(assert (not terminated-normally) "early termination failure 3")) (assert (not terminated-normally) "early termination failure 3"))
# Deadline with interrupt (let [f (coro (forever :foo))]
(defmacro with-deadline2
``
Create a fiber to execute `body`, schedule the event loop to cancel
the task (root fiber) associated with `body`'s fiber, and start
`body`'s fiber by resuming it.
The event loop will try to cancel the root fiber if `body`'s fiber
has not completed after at least `sec` seconds.
`sec` is a number that can have a fractional part.
``
[sec & body]
(with-syms [f]
~(let [,f (coro ,;body)]
(,ev/deadline ,sec nil ,f true)
(,resume ,f))))
(for i 0 10
# (print "deadline 1 iteration " i)
(assert (= :done (with-deadline2 10
(ev/sleep 0.01)
:done)) "deadline with interrupt exits normally"))
(for i 0 10
# (print "deadline 2 iteration " i)
(let [f (coro (forever :foo))]
(ev/deadline 0.01 nil f true) (ev/deadline 0.01 nil f true)
(assert-error "deadline expired" (resume f)))) (assert-error "deadline expired" (resume f)))
# Use :err :stdout # Use :err :stdout
(def- subproc-code '(do (eprint "hi") (eflush) (print "there") (flush))) (def- subproc-code '(do (eprint "hi") (eflush) (print "there") (flush)))

View File

@@ -1,58 +0,0 @@
# Copyright (c) 2025 Calvin Rose & contributors
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
(import ./helper :prefix "" :exit true)
(start-suite)
# Issue #1629
(def thread-channel (ev/thread-chan 100))
(def super (ev/thread-chan 10))
(defn worker []
(while true
(def item (ev/take thread-channel))
(when (= item :deadline)
(ev/deadline 0.1 nil (fiber/current) true))))
(ev/thread worker nil :n super)
(ev/give thread-channel :item)
(ev/sleep 0.05)
(ev/give thread-channel :item)
(ev/sleep 0.05)
(ev/give thread-channel :deadline)
(ev/sleep 0.05)
(ev/give thread-channel :item)
(ev/sleep 0.05)
(ev/give thread-channel :item)
(ev/sleep 0.15)
(assert (deep= '(:error "deadline expired" nil) (ev/take super)) "deadline expirataion")
# Another variant
(def thread-channel (ev/thread-chan 100))
(def super (ev/thread-chan 10))
(defn worker []
(while true
(def item (ev/take thread-channel))
(when (= item :deadline)
(ev/deadline 0.1))))
(ev/thread worker nil :n super)
(ev/give thread-channel :deadline)
(ev/sleep 0.2)
(assert (deep= '(:error "deadline expired" nil) (ev/take super)) "deadline expirataion")
(end-suite)

View File

@@ -136,8 +136,5 @@
"keyword slice") "keyword slice")
(assert (= 'symbol (symbol/slice "some_symbol_slice" 5 11)) "symbol slice") (assert (= 'symbol (symbol/slice "some_symbol_slice" 5 11)) "symbol slice")
# Check string formatting, #1600
(assert (= "" (string/format "%.99s" @"")) "string/format %s buffer")
(end-suite) (end-suite)

View File

@@ -37,12 +37,6 @@
Version="$(var.Version)" Version="$(var.Version)"
Manufacturer="$(var.Manufacturer)" Manufacturer="$(var.Manufacturer)"
UpgradeCode="$(var.UpgradeCode)"> UpgradeCode="$(var.UpgradeCode)">
<!--
perUser means destination will be under user's %AppData% directory,
not Program Files or similar.
see: https://learn.microsoft.com/en-us/windows/win32/msi/installation-context
-->
<Package Compressed="yes" <Package Compressed="yes"
InstallScope="perUser" InstallScope="perUser"
Manufacturer="$(var.Manufacturer)" Manufacturer="$(var.Manufacturer)"