Compare commits

...

89 commits

Author SHA1 Message Date
Daniel Kochmański
671e578c7e [nucl] smaller stacks 2025-11-30 21:24:51 +01:00
Daniel Kochmański
3b25b8c8b4 [nucl] fix the compiled code size and cleanup the dictionary
Previously we've wrongly estimated that the vector with opcodes has the same
length as the number of words, but:

CALLW takes an argument denoting the index of the function on data stack
PUSHQ takes an argument denoting the index of the literal on data stack

Moreover rename some dictionary entries for more descriptive names and add a new
word .V that prints values stored in the environment.
2025-11-30 21:24:51 +01:00
Daniel Kochmański
d7d446bfff [nucl] _nucl_word_dispatch use a stack-allocated frame
nucl_stack_frame is not always defined when we call to this function.
2025-11-30 21:24:51 +01:00
Daniel Kochmański
4880d93a6d [nucl] add all opcodes to the dictionary 2025-11-30 21:24:51 +01:00
Daniel Kochmański
ae20397968 [nucl] words operate directly on the stack
In the first sketch they operated on stack frames, but this approach was flawed
because a) leaving things on the stack above frame prevented it from growing
leading to an internal error, b) closing the frame wiped all values deposited on
the stack that were above the frame base.
2025-11-30 21:24:51 +01:00
Daniel Kochmański
cd89c1f432 [nucl] write a forth compiler 2025-11-30 21:24:51 +01:00
Daniel Kochmański
ebab441f31 [nucl] add a (mock for now) function nucl_compile_definition 2025-11-30 21:24:51 +01:00
Daniel Kochmański
0fcb28f3cb [nucl] don't modify VALUES vector and use dynamic STDIN/STDOUT vals 2025-11-30 21:24:51 +01:00
Daniel Kochmański
fcd91a20c2 [nucl] liberate stack frames from stack allocation terror 2025-11-30 21:24:51 +01:00
Daniel Kochmański
8eb45e7041 [nucl] don't pop if the item was not added 2025-11-30 21:24:51 +01:00
Daniel Kochmański
113f22b6a8 [nucl] clean up the file (move things around) 2025-11-30 21:24:51 +01:00
Daniel Kochmański
01e6c4ef27 [nucl] implement word definition 2025-11-30 21:24:51 +01:00
Daniel Kochmański
9a57760a54 [nucl] add a compilation mode (doesn't actually compile yet) 2025-11-30 21:24:51 +01:00
Daniel Kochmański
5f61baef64 [nucl] resolve words only when called, otherwise return symbols
This is necessary for defining new words and allows us to move the dictionary
implementation after the reader.
2025-11-30 21:24:51 +01:00
Daniel Kochmański
f23b46bbbd [nucl] add to the dictionary word pop 2025-11-30 21:24:51 +01:00
Daniel Kochmański
013075a8d7 [nucl] reorganize file and add "print stack" word 2025-11-30 21:24:51 +01:00
Daniel Kochmański
7bf3a380f3 [nucl] allow calling into words and properly maintain the stack
This commit takes a correction over things corrected (and rebased) in
refactor-stacks branch.

consturctors nucl_stack_to_foo remove elements from the stack and leave the
parsed element on the stack.

Move specials at the beginning.
2025-11-30 21:24:51 +01:00
Daniel Kochmański
903c4c44e8 [nucl] fix eof issues and add reading the line of objects 2025-11-30 21:24:51 +01:00
Daniel Kochmański
43e4187034 [nucl] allow extending the dictionary and make it a special variable 2025-11-30 21:24:51 +01:00
Daniel Kochmański
7ca2fc29ab [nucl] add a provisionary symbol dictionary 2025-11-30 21:24:51 +01:00
Daniel Kochmański
fd2af0ad73 [nucl] add a proto-repl without eval step 2025-11-30 21:24:51 +01:00
Daniel Kochmański
df436f5139 [nucl] use the data stack 2025-11-30 21:24:51 +01:00
Daniel Kochmański
a44cb96fa5 [nucl] skip whitespace in the reader 2025-11-30 21:24:51 +01:00
Daniel Kochmański
e47f37a104 [nucl] parse fixnums and hexnums 2025-11-30 21:24:51 +01:00
Daniel Kochmański
0bd275dd30 [nucl] implement basic reader and writer 2025-11-30 21:24:51 +01:00
Daniel Kochmański
82b0b415f6 [nucl] stacks: add a few unsafe operations 2025-11-30 21:24:51 +01:00
Daniel Kochmański
361a65e0b5 [nucl] add barebones reader 2025-11-30 21:24:51 +01:00
Daniel Kochmański
da85aeb104 [nucl] strm_nucl implement unread char 2025-11-30 21:24:51 +01:00
Daniel Kochmański
b07dc53b34 [nucl] add Lali-ho I/O 2025-11-30 21:24:51 +01:00
Daniel Kochmański
bd65f0c4cc [nucl] implement a barebones stream 2025-11-30 21:24:51 +01:00
Daniel Kochmański
da7ff0e8bf [nucl] add a mock stream 2025-11-30 21:24:51 +01:00
Daniel Kochmański
0058af914f [bytevm] [wip] new opcode CALLW, don't use lcl frame when no locals
CALLW calls a word from the data stack. The word differs from normal functions
in that it takes no arguments (so the call does not modify the data stack).

To allow words using the stack across calls (like in "real" forth) don't unwind
the stack on exit if there are no locals.
2025-11-30 21:24:39 +01:00
Daniel Kochmański
69b8ef4842 stream: port stream.d so it can be used with early env
This is a step towards introducing the I/O system.
2025-11-30 21:22:56 +01:00
Daniel Kochmański
98b887a7ea [nucl] showcase calling into ecl_interpret 2025-11-30 21:22:56 +01:00
Daniel Kochmański
d706faa600 nucleus: build nucleus directly from .c files (not .o) 2025-11-30 21:22:56 +01:00
Daniel Kochmański
d1241fbe02 [bytevm][wip] bytevm: allocate stack manually
wip tag because:

- we don't free tha stack (we use alloc_memory)
2025-11-30 21:22:56 +01:00
Daniel Kochmański
08f809d2f8 [wip] memory: ensure disabled interrupts in top-level operators
ecl_alloc_object, ecl_free_object
ecl_alloc, ecl_alloc_manual, ecl_alloc_atomic, ecl_dealloc

Moreover move all top-level ops to memory.d so they are not reliant on mem_gc.
The stubbed allocator uses manual memory managament for all ops.

[wip] because we should adjust ecl_make_stack too
2025-11-30 21:22:56 +01:00
Daniel Kochmański
6232de673d type_info: reify the type_info database
We store information about the object size, its pointers and name. This
information is later reused by the garbage collector.
2025-11-30 21:22:56 +01:00
Daniel Kochmański
71d8535442 nucleus: move ecl_cons to memory.d
ecl_cons requires a separate allocator because it may be a small cons.
2025-11-30 21:22:56 +01:00
Daniel Kochmański
d58bab2a26 memory: make it possible to configure the allocator 2025-11-30 21:22:56 +01:00
Daniel Kochmański
24edc0a250 [wip] nucl: binary and preliminary notes 2025-11-30 21:22:56 +01:00
Daniel Kochmański
562df3f4b3 msvc: update the makefile and specify /std:c11 minimal standard
MSVC does not allow for specifying /std:c99 so we need c11. We don't rely on the
default standard because it does not allow for static struct initializers.
2025-11-30 21:22:56 +01:00
Daniel Kochmański
c772ea3073 nucleus: move ecl_eql to a separate file
This is a low-level comparison operator. We opencode EQL comparison for bignums
to avoid a dependency on GMP (in this file).
2025-11-30 21:22:56 +01:00
Daniel Kochmański
f41fb2ae38 nucleus: introduce a table with early symbols ecl_symbols
This table contains symbols that are essential to the core runtime: ECL_T,
ECL_UNBOUND, ECL_SIGNAL_HANDLERS, ECL_RESTART_CLUSTERs, ECL_INTERRUPTS_ENABLED,
ECL_ALLOW_OTHER_KEYS and ECL_UNBOUND.

The table is initialized with constexpr, so it is possible to use its elements
in static elements. We also add ecl_def_function to ecl-inl to allow
appropriating C functions into Lisp world at top level.
2025-11-30 21:22:56 +01:00
Daniel Kochmański
0fa2095bd8 nucleus: move early stacks to a separate file
This is necessary if we want to link them into nucleus without CL env baggage.
2025-11-30 21:22:53 +01:00
Daniel Kochmański
9c6f31f408 nucleus: move aux throw/go/tagbody implementations to jump.d 2025-11-30 21:20:40 +01:00
Daniel Kochmański
e10bb675b0 modules: uninstall signal handlers when unixint is destroyed 2025-11-30 21:20:40 +01:00
Daniel Kochmański
0ce6adb1c2 modules: deallocate stacks when modules are destroyed 2025-11-30 21:20:40 +01:00
Daniel Kochmański
156704b5dd modules: release all resources on ecl_halt
Previously we were lazy and simply marked the runtime as "not booted", but now
we do perform a proper shutdown.
2025-11-30 21:20:40 +01:00
Daniel Kochmański
8432685284 process: move process initialization to the process module hooks 2025-11-30 21:20:40 +01:00
Daniel Kochmański
8573c58768 garbage: register and unregister GC threads manually from a module
This decouples thread primitives from the garbage collector and allows us to
build nucl once more.
2025-11-30 21:20:40 +01:00
Daniel Kochmański
511389c126 process: abstract away create thread, exit thread and sigmask
Previously we've opencoded calls to these functions, although they may be nicely
abstracted with static inline functions. This change improves code readibility
and portability.
2025-11-30 21:20:40 +01:00
Daniel Kochmański
f567c1829e modules: [A/n] move the environment allocators to nucleus
Also clean up initialization code across different paths to have the same order.
2025-11-30 21:20:40 +01:00
Daniel Kochmański
5e20d8bd9a modules: [9/n] introduce ecl_module_thread 2025-11-30 21:20:39 +01:00
Daniel Kochmański
c488a5ffd3 modules: [7/n] introduce ecl_module_stacks 2025-11-30 21:20:39 +01:00
Daniel Kochmański
e550aad6ef modules: [6/n] introduce ecl_module_aux 2025-11-30 21:20:39 +01:00
Daniel Kochmański
13e14742a6 modules: [5/n] introduce ecl_module_ffi 2025-11-30 21:20:39 +01:00
Daniel Kochmański
9c1ae979f4 modules: [4/n] introduce ecl_module_bignum 2025-11-30 21:20:39 +01:00
Daniel Kochmański
46b0aa512d modules: [3/n] introduce ecl_module_process 2025-11-30 21:20:39 +01:00
Daniel Kochmański
10c03bedfc modules: [2/n] introduce ecl_module_unixint 2025-11-30 21:20:39 +01:00
Daniel Kochmański
05255a56e9 modules: [1/n] introduce ecl_module_gc
We also remove conditionalization for garbage collector inclusion in autotools.
When we propose an alternative gc, then we may decide to put them back, or to
add necessary ifdef statements directly in files.

Moreover untangle c-stack from the gc code and assign the stack base with a
rough guess only when it is not initialized yet (GC will always fill it).

Finally remove a kludge from ecl_adopt_cpu and disable colleciton until the cpu
is fully initialized.
2025-11-30 21:20:39 +01:00
Daniel Kochmański
dabaf19c2d modules: [0/n] introduce a new structure ecl_module in the system
This will allow us to decouple forward system initialization from the early
process code.
2025-11-30 21:20:39 +01:00
Daniel Kochmański
9cf792a9ee process: move ecl_clear_bignum_registers to _dealloc_env
This resolves a fixme.
2025-11-30 21:20:39 +01:00
Daniel Kochmański
9ff07f7667 process: use GC_thread_is_registered() instead of the_env->cleanup
This allows us to remove unnecessary bookkeeping.
2025-11-30 21:20:39 +01:00
Daniel Kochmański
d990d2afd5 nucleus: [2/n] move processing unit managament to nucleus 2025-11-30 21:20:39 +01:00
Daniel Kochmański
71d5f8dd78 nucleus: [1/n] move processing unit managament to nucleus 2025-11-30 21:20:39 +01:00
Daniel Kochmański
6fb1b5e9e1 exceptions: define *SIGNAL-HANDLERS* in cold_boot
I've also renamed *HANDLER-CLUSTERS* to a more appropriate *SIGNAL-HANDLERS*.
Currently this symbol is imported to the SYSTEM package, although this may be
revised in the future to cater to multiple global environments. Alternatively
the SYSTEM package may be common to all runtimes.
2025-11-30 21:20:39 +01:00
Daniel Kochmański
5ce3a2be4d exceptions: dispatch signals exceptions (not conditions) 2025-11-30 21:20:39 +01:00
Daniel Kochmański
15013d2352 exceptions: runtime stack error signals exceptions (not conditions)
Replace calls to CEstack_overflow with exceptions - this is a necessary step
before moving stacks into nucleus.
2025-11-30 21:20:39 +01:00
Daniel Kochmański
4320237c6a exceptions: interpreter signals exceptions (not conditions) 2025-11-30 21:20:39 +01:00
Daniel Kochmański
7bc1bade1b exceptions: introduce the concept of an exception
The exception in CL is resignaled as a condition.
2025-11-30 21:20:39 +01:00
Daniel Kochmański
a64870cb72 exceptions: introduce signals to the early environment 2025-11-30 21:20:39 +01:00
Daniel Kochmański
90d6e21697 exceptions: rewrite signal handling to use functions and not lists
Instead of storing lists in *HANDLER-CLUSTERS*, we define functions that are
called unconditionally on the handler. HANDLER-BIND defines that function to be
a typecase that is dispatched based on the conditiont type, as specified by CL.

This change will aid further refactor.
2025-11-30 21:20:39 +01:00
Daniel Kochmański
a2021f1afd nucleus: move ecl_core_struct to nucleus 2025-11-30 21:20:39 +01:00
Daniel Kochmański
6f07bed6c7 nucleus: move protect and dummy tags to boot.d 2025-11-30 21:20:39 +01:00
Daniel Kochmański
0d986c58d6 nucleus: move early constants from main.d to boot.d 2025-11-30 21:20:39 +01:00
Daniel Kochmański
617680e4d5 nucleus: add a module boot for booting the core
Currently it contains only option setters.
2025-11-30 21:20:39 +01:00
Daniel Kochmański
fc68057fc0 core: add a module for program control transfer
Currently it contains early errors and backtrace.
2025-11-30 21:20:39 +01:00
Daniel Kochmański
be5aa38bd1 apply: move funcall and apply-from-stack eval.d -> apply.d 2025-11-30 21:20:39 +01:00
Daniel Kochmański
e40849cfd3 core: split cl_core_struct in two structure cl_core and ecl_core
ecl_core contains early global environment that is meant to be shared by all
runtimes, while cl_core contains an environment relevant to common lisp.
2025-11-30 21:20:39 +01:00
Daniel Kochmański
a7f71259ed core: define protect and dummy tags as constants
Both tags have a special meaning to the low-level runtime (most notably the
frame stack). Extracting them from "all symbols" is a step towards multiple
runtimes.
2025-11-30 21:20:39 +01:00
Daniel Kochmański
9314e8b192 core: move defacto constants from cl_core structure to global space 2025-11-30 21:20:39 +01:00
Marius Gerbershagen
855f93431b Merge branch 'fix-799' into 'develop'
Fix :variables command in top-level env

Closes #799

See merge request embeddable-common-lisp/ecl!359
2025-11-30 14:52:28 +00:00
Daniel Kochmański
9f9c9a8037 cmp: assign _ecl_debug_env to lcl_env (not lex_env) 2025-11-29 22:22:41 +01:00
Daniel Kochmański
dfb691ede8 top: add captured records to the local environment
We include captured functions, blocks and variables along with local
variables. This fixes #799.

Moreover DECODE-IHS-ENV is deperacated and more DWIM:
- calls DECODE-IHS-LOCALS for old arguments
- appends DECODE-IHS-LOCALS and DECODE-IHS-LEXENV for ihs index

DECODE-IHS-LOCALS and DECODE-IHS-LEXENV are responsible for decoding appropriate
environments.
2025-11-28 13:13:04 +01:00
Daniel Kochmański
e6ae6146a4 ihs/swank: make si_ihs_env return the local environment (not lexical)
We deprecate the function si_ihs_env in favor of more explicit si_ihs_lex and
si_ihs_lcl, but the former is left for backward compatibility with SLIME/SLYNK
because they call it to query the environment to add locals to the backtrace.
2025-11-28 11:57:09 +01:00
Daniel Kochmański
8a5007fd4a top: separate correctly lexenv from lclenv in break environment
Fixes #799.
2025-11-28 11:57:09 +01:00
Daniel Kochmański
ed5471169e ihs: store locals and lexical environment in separate slots
Since ~recently we store local variables in the bytevm on the stack.  Also, the
native comipler under specified debug options, stores locals in ihs, but it has
nothing to do with the lexical environment. So it feels justified to push both
to a separate field.
2025-11-28 11:57:09 +01:00
Daniel Kochmański
3c4c1639c5 proclamations: fix an invalid proclamation for SI:IHS-ENV
It may seem like this proclamation is invalid sincd !346, but the divergence
happens much earlier. 8c0314022c introduces a
feature where c-compiled code can also add debug information, and in that case
the environment is a vector, so the proclamation back then should be:

  (proclamation si:ihs-env (si::index) (or list vector))

Later when we've changed the representation, it should be changed to

  (proclamation si:ihs-env (si::index) (or null vector))

Where NULL denotes "no lexical environment".
2025-11-28 11:57:09 +01:00
80 changed files with 6336 additions and 3456 deletions

View file

@ -137,7 +137,7 @@ GCFLAGS = nodebug=1
CLIBS = $(CLIBS) DbgHelp.lib
!endif
CFLAGS = /EHsc /DGC_DLL /DGC_BUILD /nologo /wd4068 /wd4715 /wd4716 /D_CRT_SECURE_NO_DEPRECATE $(CFLAGS_CONFIG)
CFLAGS = /EHsc /DGC_DLL /DGC_BUILD /nologo /wd4068 /wd4715 /wd4716 /D_CRT_SECURE_NO_DEPRECATE /std:c11 $(CFLAGS_CONFIG)
LDFLAGS = /link /incremental:no /nologo $(LDFLAGS_CONFIG) /STACK:$(ECL_DEFAULT_C_STACK_SIZE)

View file

@ -47,7 +47,7 @@ ECL_USE_DBGHELP_FLAG=0
# Programs used by "make":
#
CC = cl
CFLAGS = -c $(ECL_CFLAGS) -DECL_BUILD -DECL_API="__declspec(dllexport)" -I./ -I../ -I../ecl -I$(srcdir) -I$(srcdir)/unicode
CFLAGS = -c $(ECL_CFLAGS) /std:c11 -DECL_BUILD -DECL_API="__declspec(dllexport)" -I./ -I../ -I../ecl -I$(srcdir) -I$(srcdir)/unicode
SHELL = /bin/sh
RM = del
@ -79,6 +79,9 @@ HFILES = ..\ecl\config.h ..\ecl\config-internal.h ..\ecl\atomic_ops.h \
$(HDIR)\cache.h $(HDIR)\stack-resize.h \
$(HDIR)\ecl_atomics.h
NUCL_OBJS = boot.obj call.obj jump.obj atomic.obj process.obj memory.obj \
module.obj stacks.obj
CLOS_OBJS = cache.obj accessor.obj instance.obj gfun.obj
NUM_OBJS = number.obj num_pred.obj num_arith.obj num_co.obj num_log.obj num_rand.obj \
@ -112,7 +115,7 @@ OBJS = main.obj symbol.obj package.obj cons.obj list.obj apply.obj eval.obj \
backq.obj stacks.obj time.obj unixint.obj mapfun.obj multival.obj hash.obj \
format.obj pathname.obj structure.obj load.obj unixfsys.obj unixsys.obj \
serialize.obj atomic.obj process.obj \
big.obj alloc_2.obj tcp.obj \
big.obj mem_gc.obj tcp.obj \
$(BOOT_OBJS) $(NUM_OBJS) $(WRITER_OBJS) $(READER_OBJS) $(STREAM_OBJS) \
$(CLOS_OBJS) $(FFI_OBJS) $(THREADS_OBJ) $(ECL_UCD_OBJ) $(ECL_SSE_OBJ)

10
nucl.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/sh
rm -f nucl
pushd build/c
make nucl
mv nucl ../../
popd
./nucl

View file

@ -136,7 +136,7 @@ $(ECL_MIN): $(LIBRARIES) .gdbinit libeclmin.a
if [ -f CROSS-COMPILER ]; then \
touch $@; \
else \
$(CC) $(LDFLAGS) -o $@ \
$(CC) $(LDFLAGS) -rdynamic -o $@ \
cinit.o c/all_symbols.o \
-L./ libeclmin.a \
$(CORE_LIBS) $(FASL_LIBS) $(LIBS);\

29
src/aclocal.m4 vendored
View file

@ -274,9 +274,10 @@ SHAREDPREFIX='lib'
LIBPREFIX='lib'
LIBEXT='a'
PICFLAG='-fPIC'
THREAD_CFLAGS=''
THREAD_CFLAGS='-DGC_NO_THREAD_REDIRECTS'
THREAD_LIBS=''
THREAD_GC_FLAGS='--enable-threads=posix'
CFLAGS=''
INSTALL_TARGET='install'
THREAD_OBJ="$THREAD_OBJ threads/thread threads/mutex threads/condition_variable threads/semaphore threads/barrier threads/mailbox threads/rwlock"
clibs='-lm'
@ -285,7 +286,7 @@ SONAME_LDFLAGS=''
case "${host_os}" in
linux-android*)
thehost='ANDROID'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
ECL_LDRPATH='-Wl,--rpath,~A'
@ -300,7 +301,7 @@ case "${host_os}" in
# libdir may have a dollar expression inside
linux*)
thehost='linux'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_LIBS='-lpthread'
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
@ -314,7 +315,7 @@ case "${host_os}" in
;;
gnu*)
thehost='gnu'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_LIBS='-lpthread'
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
@ -327,7 +328,7 @@ case "${host_os}" in
;;
kfreebsd*-gnu)
thehost='kfreebsd'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_LIBS='-lpthread'
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
@ -377,8 +378,6 @@ case "${host_os}" in
;;
openbsd*)
thehost='openbsd'
THREAD_CFLAGS=''
THREAD_LIBS=''
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
ECL_LDRPATH="-Wl,--rpath,~A"
@ -409,7 +408,7 @@ case "${host_os}" in
thehost='cygwin'
#enable_threads='no'
shared='yes'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_LIBS='-lpthread'
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
@ -431,7 +430,7 @@ case "${host_os}" in
clibs=''
shared='yes'
enable_threads='yes'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_GC_FLAGS='--enable-threads=win32'
SHARED_LDFLAGS="-Wl,--stack,${ECL_DEFAULT_C_STACK_SIZE}"
BUNDLE_LDFLAGS="-Wl,--stack,${ECL_DEFAULT_C_STACK_SIZE}"
@ -460,7 +459,7 @@ case "${host_os}" in
SHARED_LDFLAGS="-dynamiclib ${LDFLAGS}"
BUNDLE_LDFLAGS="-bundle ${LDFLAGS}"
ECL_LDRPATH='-Wl,-rpath,~A'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_LIBS='-lpthread'
# The GMP library has not yet been ported to Intel or Arm-OSX
case "`uname -m`" in
@ -498,7 +497,7 @@ case "${host_os}" in
thehost='nonstop'
shared='yes'
PICFLAG='-call_shared'
THREAD_CFLAGS='-spthread'
THREAD_CFLAGS="-spthread ${THREAD_CFLAGS}"
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
ECL_LDRPATH='-Wld=\"-rld_l ~A\"'
@ -506,7 +505,6 @@ case "${host_os}" in
;;
haiku*)
thehost='haiku'
THREAD_LIBS=''
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
ECL_LDRPATH="-Wl,--rpath,~A"
@ -535,7 +533,7 @@ esac
case "${host}" in
*-nacl)
thehost='linux'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_LIBS='-lpthread'
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
@ -547,7 +545,7 @@ case "${host}" in
;;
*-pnacl)
thehost='linux'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_LIBS='-lpthread'
dnl SHARED_LDFLAGS="-shared ${LDFLAGS}"
dnl BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
@ -1196,7 +1194,6 @@ if test "${enable_boehm}" = auto -o "${enable_boehm}" = system; then
fi
else
FASL_LIBS="${FASL_LIBS} -lgc"
EXTRA_OBJS="${EXTRA_OBJS} alloc_2.${OBJEXT}"
AC_DEFINE(GBC_BOEHM, [1], [Use Boehm's garbage collector])
fi
fi
@ -1228,7 +1225,6 @@ if test "${enable_boehm}" = "included"; then
ECL_BOEHM_GC_HEADER='ecl/gc/gc.h'
SUBDIRS="${SUBDIRS} gc"
CORE_LIBS="-leclgc ${CORE_LIBS}"
EXTRA_OBJS="${EXTRA_OBJS} alloc_2.${OBJEXT}"
if test "${enable_shared}" = "no"; then
LIBRARIES="${LIBRARIES} ${LIBPREFIX}eclgc.${LIBEXT}"
fi
@ -1304,7 +1300,6 @@ if test "${enable_libffi}" = "included"; then
ECL_LIBFFI_HEADER='ecl/ffi.h'
SUBDIRS="${SUBDIRS} libffi"
CORE_LIBS="-leclffi ${CORE_LIBS}"
EXTRA_OBJS="${EXTRA_OBJS} alloc_2.${OBJEXT}"
if test "${enable_shared}" = "no"; then
LIBRARIES="${LIBRARIES} ${LIBPREFIX}eclffi.${LIBEXT}"
fi

View file

@ -7,6 +7,7 @@
top_srcdir= @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
builddir= @true_builddir@
# Programs used by "make":
#
@ -50,7 +51,14 @@ HFILES = $(HDIR)/config.h $(HDIR)/ecl.h $(HDIR)/ecl-cmp.h $(HDIR)/object.h
$(HDIR)/impl/math_dispatch.h $(HDIR)/impl/math_fenv.h \
$(HDIR)/impl/math_fenv_msvc.h $(HDIR)/nucleus.h
BOOT_OBJS =
NUCL_CFLG = -DECL_NUCL -DECL_BUILD -DGC_NO_THREAD_REDIRECTS \
-I$(builddir) -I$(srcdir) -g3 -rdynamic
NUCL_SRCS = boot.c escape.c module.c stacks.c eql.c \
memory.c atomic.c process.c apply.c interpreter.c stream.c \
streams/strm_nucl.c
BOOT_OBJS = boot.o escape.o module.o stacks.o eql.o
CLOS_OBJS = clos/cache.o clos/accessor.o clos/instance.o clos/gfun.o
@ -81,9 +89,10 @@ FFI_OBJS = ffi.o ffi/libraries.o ffi/backtrace.o ffi/mmap.o ffi/cdata.o
OBJS = main.o symbol.o package.o cons.o list.o apply.o eval.o interpreter.o \
compiler.o disassembler.o reference.o character.o error.o \
string.o cfun.o typespec.o assignment.o memory.o predicate.o array.o \
vector_push.o sequence.o cmpaux.o macros.o backq.o stacks.o time.o \
vector_push.o sequence.o cmpaux.o macros.o backq.o stack2.o time.o \
unixint.o mapfun.o multival.o hash.o format.o pathname.o structure.o \
load.o unixfsys.o unixsys.o serialize.o sse2.o atomic.o process.o \
mem_gc.o \
$(BOOT_OBJS) $(NUM_OBJS) $(WRITER_OBJS) $(READER_OBJS) $(STREAM_OBJS) \
$(CLOS_OBJS) $(FFI_OBJS) @EXTRA_OBJS@
@ -110,6 +119,9 @@ $(HDIR)/%.h: $(top_srcdir)/h/%.h
%.o: %.c $(HFILES)
$(CC) -DECLDIR="\"@ecldir@\"" $(CFLAGS) -o $@ $<
nucl: $(NUCL_SRCS) nucl.c
$(CC) $(NUCL_CFLG) -o $@ $^
../libeclmin.a: $(OBJS) all_symbols.o all_symbols2.o
$(RM) $@
$(AR) cr $@ $(OBJS)

View file

@ -292,8 +292,8 @@ init_all_symbols(void)
cl_object s, value;
cl_objectfn fun;
/* We skip NIL and T */
for (i = 2; cl_symbols[i].init.name != NULL; i++) {
/* We skip ECL_NIL_SYMBOL */
for (i = 1; cl_symbols[i].init.name != NULL; i++) {
s = (cl_object)(cl_symbols + i);
code = cl_symbols[i].init.type;
name = cl_symbols[i].init.name;

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,90 @@
*/
#include <ecl/ecl.h>
#include <ecl/ecl-inl.h>
#include <ecl/internal.h>
#include <ecl/external.h>
#include <ecl/nucleus.h>
cl_objectfn
ecl_function_dispatch(cl_env_ptr env, cl_object x)
{
cl_object fun = x;
if (ecl_unlikely(fun == ECL_NIL))
ecl_ferror(ECL_EX_F_UNDEF, fun, ECL_NIL);
switch (ecl_t_of(fun)) {
case t_cfunfixed:
env->function = fun;
return fun->cfunfixed.entry;
case t_cfun:
env->function = fun;
return fun->cfun.entry;
case t_cclosure:
env->function = fun;
return fun->cclosure.entry;
case t_instance:
env->function = fun;
return fun->instance.entry;
case t_symbol:
fun = ECL_SYM_FUN(fun);
env->function = fun;
return fun->cfun.entry;
case t_bytecodes:
env->function = fun;
return fun->bytecodes.entry;
case t_bclosure:
env->function = fun;
return fun->bclosure.entry;
default:
ecl_ferror(ECL_EX_F_INVAL, fun, ECL_NIL);
}
_ecl_unexpected_return();
}
/* Calling conventions:
* Compiled C code calls lisp function supplying #args, and args.
*
* Linking function performs check_args, gets jmp_buf with _setjmp, then
*
* if cfun then stores C code address into function link location and transfers
* to jmp_buf at cf_self
* if cclosure then replaces #args with cc_env and calls cc_self otherwise, it
* emulates funcall.
*/
cl_object
ecl_apply_from_stack_frame(cl_object frame, cl_object x)
{
cl_object *sp = ECL_STACK_FRAME_PTR(frame);
cl_index narg = frame->frame.size;
cl_env_ptr env = frame->frame.env;
cl_objectfn entry = ecl_function_dispatch(env, x);
cl_object ret;
env->stack_frame = frame;
ret = APPLY(narg, entry, sp);
env->stack_frame = NULL;
return ret;
}
cl_object
cl_funcall(cl_narg narg, cl_object function, ...)
{
cl_object output;
--narg;
{
ECL_STACK_FRAME_VARARGS_BEGIN(narg, function, frame);
output = ecl_apply_from_stack_frame(frame, function);
ECL_STACK_FRAME_VARARGS_END(frame);
}
return output;
}
cl_object *
_ecl_va_sp(cl_narg narg)
{
return ECL_STACK_FRAME_PTR(ecl_process_env()->stack_frame) + narg;
}
#if !(ECL_C_ARGUMENTS_LIMIT == 63)
#error "Please adjust code to the constant!"
@ -656,6 +739,7 @@ APPLY_fixed(cl_narg n, cl_object (*fn)(), cl_object *x)
x[50],x[51],x[52],x[53],x[54],x[55],x[56],
x[57],x[58],x[59],x[60],x[61],x[62]);
default:
FEprogram_error("Too many arguments", 0);
ecl_ferror(ECL_EX_F_NARGS, ecl_make_fixnum(n), ECL_NIL);
}
_ecl_unexpected_return();
}

View file

@ -14,10 +14,13 @@
*/
#define ECL_INCLUDE_MATH_H
#include <ecl/ecl.h>
#include <ecl/ecl-inl.h>
#include <ecl/internal.h>
#include <ecl/external.h>
#include <limits.h>
#include <string.h>
#include <ecl/ecl.h>
#include <ecl/internal.h>
/*************************************************************
* MEMORY MANAGEMENT WITH GMP
@ -39,9 +42,7 @@
*
* The GMP library may also allocate temporary memory for its
* computations. It is configurable at runtime whether we use malloc
* and free or the corresponding equivalents from the garbage
* collector (ecl_alloc_uncollectable and ecl_free_uncollectable) for
* that.
* and free or the corresponding equivalents from the GC.
*/
/*************************************************************
@ -326,22 +327,20 @@ _ecl_fix_divided_by_big(cl_fixnum x, cl_object y)
static void *
mp_alloc(size_t size)
{
return ecl_alloc_uncollectable(size);
return ecl_malloc(size);
}
static void
mp_free(void *ptr, size_t size)
{
ecl_free_uncollectable(ptr);
ecl_free(ptr);
}
static void *
mp_realloc(void *ptr, size_t osize, size_t nsize)
{
mp_limb_t *p = mp_alloc(nsize);
memcpy(p, ptr, (osize < nsize)? osize : nsize);
mp_free(ptr, osize);
return p;
ptr = ecl_realloc(ptr, osize, nsize);
return ptr;
}
#ifdef ECL_GMP_FIXNUM_TO_LIMBS
@ -607,29 +606,52 @@ _ecl_big_boole_operator(int op)
return bignum_operations[op];
}
void
/* -- module definition ------------------------------------------------------ */
static cl_object
create_bignum ()
{
if (ecl_option_values[ECL_OPT_SET_GMP_MEMORY_FUNCTIONS])
mp_set_memory_functions(mp_alloc, mp_realloc, mp_free);
return ECL_NIL;
}
cl_object
ecl_init_bignum_registers(cl_env_ptr env)
{
int i;
for (i = 0; i < ECL_BIGNUM_REGISTER_NUMBER; i++) {
/* INV this implies the standard allocator already initialized. */
cl_object x = ecl_alloc_object(t_bignum);
_ecl_big_init2(x, ECL_BIG_REGISTER_SIZE);
env->big_register[i] = x;
}
return ECL_NIL;
}
void
ecl_clear_bignum_registers(cl_env_ptr env)
cl_object
ecl_free_bignum_registers(cl_env_ptr env)
{
int i;
for (i = 0; i < ECL_BIGNUM_REGISTER_NUMBER; i++) {
_ecl_big_clear(env->big_register[i]);
env->big_register[i] = ECL_NIL;
}
return ECL_NIL;
}
void
init_big()
{
if (ecl_option_values[ECL_OPT_SET_GMP_MEMORY_FUNCTIONS])
mp_set_memory_functions(mp_alloc, mp_realloc, mp_free);
}
ecl_def_ct_base_string(str_bignum, "BIGNUM", 6, static, const);
static struct ecl_module module_bignum = {
.name = str_bignum,
.create = create_bignum,
.enable = ecl_module_no_op,
.init_env = ecl_init_bignum_registers,
.init_cpu = ecl_module_no_op_cpu,
.free_cpu = ecl_module_no_op_cpu,
.free_env = ecl_free_bignum_registers,
.disable = ecl_module_no_op,
.destroy = ecl_module_no_op
};
cl_object ecl_module_bignum = (cl_object)&module_bignum;

295
src/c/boot.d Normal file
View file

@ -0,0 +1,295 @@
/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* vim: set filetype=c tabstop=2 shiftwidth=2 expandtab: */
/* boot.c - initializing ecl internal data */
/* -- imports --------------------------------------------------------------- */
#include <ecl/ecl.h>
#include <ecl/ecl-inl.h>
#include <ecl/internal.h>
#include <ecl/external.h>
#ifdef ECL_USE_MPROTECT
# include <sys/mman.h>
# ifndef MAP_FAILED
# define MAP_FAILED -1
# endif
#endif
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(ECL_MS_WINDOWS_HOST)
# include <windows.h>
# include <shellapi.h>
# define MAXPATHLEN 512
#endif
#ifndef MAXPATHLEN
# ifdef PATH_MAX
# define MAXPATHLEN PATH_MAX
# else
# define MAXPATHLEN sysconf(_PC_PATH_MAX)
# include <unistd.h>
# endif
#endif
/* -- constants ----------------------------------------------------- */
const cl_object ecl_ct_Jan1st1970UT = ecl_make_fixnum(39052800);
ecl_def_ct_base_string(ecl_ct_null_string,"",0,,const);
ecl_def_ct_single_float(ecl_ct_default_rehash_size,1.5f,,const);
ecl_def_ct_single_float(ecl_ct_default_rehash_threshold,0.75f,,const);
ecl_def_ct_single_float(ecl_ct_singlefloat_zero,0,,const);
ecl_def_ct_double_float(ecl_ct_doublefloat_zero,0,,const);
ecl_def_ct_long_float(ecl_ct_longfloat_zero,0,,const);
ecl_def_ct_single_float(ecl_ct_singlefloat_minus_zero,-0.0,,const);
ecl_def_ct_double_float(ecl_ct_doublefloat_minus_zero,-0.0,,const);
ecl_def_ct_long_float(ecl_ct_longfloat_minus_zero,-0.0l,,const);
ecl_def_ct_ratio(ecl_ct_plus_half,ecl_make_fixnum(1),ecl_make_fixnum(2),,const);
ecl_def_ct_ratio(ecl_ct_minus_half,ecl_make_fixnum(-1),ecl_make_fixnum(2),,const);
/* These two tags have a special meaning for the frame stack. */
ecl_def_constant(ecl_ct_protect_tag, ECL_NIL, "PROTECT-TAG", 11);
ecl_def_constant(ecl_ct_dummy_tag, ECL_NIL, "DUMMY-TAG", 9);
struct ecl_symbol
ecl_symbols[] = {
/* This variable contains handlers for signals and exceptions. */
ecl_constexpr_symbol(ecl_stp_special, "*SIGNAL-HANDLERS*", ECL_NIL),
/* Restart clusters allow us to estabilish selectable correction actions. */
ecl_constexpr_symbol(ecl_stp_special, "*RESTART-CLUSTERS*", ECL_NIL),
/* This variable allows for interrupting sygnals from Lisp.. */
ecl_constexpr_symbol(ecl_stp_special, "*INTERRUPTS-ENABLED*", ECL_T),
/* OP_PUSHKEYS handles specially :ALLOW-OTHER-KEYS (per CL semantics). */
ecl_constexpr_symbol(ecl_stp_constant, "ALLOW-OTHER-KEYS", ECL_ALLOW_OTHER_KEYS),
/* The universal truth, the supertype of all, the class above classes. */
ecl_constexpr_symbol(ecl_stp_constant, "T", ECL_T),
/* The marker for unbound slots. This is more a tag than a symbol. */
ecl_constexpr_symbol(ecl_stp_constant, "UNBOUND", ECL_UNBOUND),
};
/* -- implementation ------------------------------------------------ */
#if ECL_FIXNUM_BITS <= 32
/* 1GB */
#define ECL_DEFAULT_HEAP_SIZE 1073741824L
#else
/* 4GB */
#define ECL_DEFAULT_HEAP_SIZE 4294967296L
#endif
#ifndef ECL_DEFAULT_C_STACK_SIZE
#define ECL_DEFAULT_C_STACK_SIZE 0
#endif
#ifdef GBC_BOEHM_GENGC
#define ECL_INCREMENTAL_GC 1
#else
#define ECL_INCREMENTAL_GC 0
#endif
#if defined(ECL_THREADS) && defined(HAVE_SIGPROCMASK)
#define ECL_SIGNAL_HANDLING_THREAD 1
#else
#define ECL_SIGNAL_HANDLING_THREAD 0
#endif
/* INV: see ecl_option enum in external.h */
cl_fixnum ecl_option_values[ECL_OPT_LIMIT+1] = {
/* ---------------------------------------------------------------- */
ECL_INCREMENTAL_GC, /* ECL_OPT_INCREMENTAL_GC */
1, /* ECL_OPT_TRAP_SIGSEGV */
1, /* ECL_OPT_TRAP_SIGFPE */
1, /* ECL_OPT_TRAP_SIGINT */
1, /* ECL_OPT_TRAP_SIGILL */
1, /* ECL_OPT_TRAP_SIGBUS */
1, /* ECL_OPT_TRAP_SIGPIPE */
1, /* ECL_OPT_TRAP_INTERRUPT_SIGNAL */
ECL_SIGNAL_HANDLING_THREAD, /* ECL_OPT_SIGNAL_HANDLING_THREAD */
16, /* ECL_OPT_SIGNAL_QUEUE_SIZE */
0, /* ECL_OPT_BOOTED */
/* ---------------------------------------------------------------- */
8192, /* ECL_OPT_BIND_STACK_SIZE */
1024, /* ECL_OPT_BIND_STACK_SAFETY_AREA */
2048, /* ECL_OPT_FRAME_STACK_SIZE */
128, /* ECL_OPT_FRAME_STACK_SAFETY_AREA */
32768, /* ECL_OPT_LISP_STACK_SIZE */
128, /* ECL_OPT_LISP_STACK_SAFETY_AREA */
ECL_DEFAULT_C_STACK_SIZE, /* ECL_OPT_C_STACK_SIZE */
4*sizeof(cl_index)*1024, /* ECL_OPT_C_STACK_SAFETY_AREA */
ECL_DEFAULT_HEAP_SIZE, /* ECL_OPT_HEAP_SIZE */
1024*1024, /* ECL_OPT_HEAP_SAFETY_AREA */
0, /* ECL_OPT_THREAD_INTERRUPT_SIGNAL */
1, /* ECL_OPT_SET_GMP_MEMORY_FUNCTIONS */
1, /* ECL_OPT_USE_SETMODE_ON_FILES */
/* ---------------------------------------------------------------- */
0};
cl_fixnum
ecl_get_option(int option)
{
if (option >= ECL_OPT_LIMIT || option < 0) {
return -1;
}
return ecl_option_values[option];
}
cl_fixnum
ecl_set_option(int option, cl_fixnum value)
{
if (option > ECL_OPT_LIMIT || option < 0) {
return -1;
}
if (option >= ECL_OPT_BOOTED || !ecl_option_values[ECL_OPT_BOOTED]) {
ecl_option_values[option] = value;
}
return ecl_option_values[option];
}
/* -- environments ---------------------------------------------------------- */
#ifdef ECL_THREADS
static void
add_env(cl_env_ptr the_env)
{
cl_object _env;
ecl_mutex_lock(&ecl_core.processes_lock);
_env = ecl_cast_ptr(cl_object,the_env);
ecl_stack_push(ecl_core.threads, _env);
ecl_mutex_unlock(&ecl_core.processes_lock);
}
static void
del_env(cl_env_ptr the_env)
{
cl_object _env;
ecl_mutex_lock(&ecl_core.processes_lock);
_env = ecl_cast_ptr(cl_object,the_env);
ecl_stack_del(ecl_core.threads, _env);
ecl_mutex_unlock(&ecl_core.processes_lock);
}
#endif
cl_env_ptr
_ecl_alloc_env(cl_env_ptr parent)
{
/* Allocates the lisp environment for a thread. Depending on which mechanism
* we use for detecting delayed signals, we may allocate the environment using
* mmap or with malloc.
*
* Note that at this point we are not allocating any other memory which is
* stored via a pointer in the environment. If we would do that, an unlucky
* interrupt by the gc before the allocated environment is registered in
* ecl_core.processes could lead to memory being freed because the gc is not
* aware of the pointer to the allocated memory in the environment. */
cl_env_ptr output;
#if defined(ECL_USE_MPROTECT)
output = (cl_env_ptr) mmap(0, sizeof(*output), PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
if (output == MAP_FAILED)
ecl_internal_error("Unable to allocate environment structure.");
#else
# if defined(ECL_USE_GUARD_PAGE)
output = VirtualAlloc(0, sizeof(*output), MEM_COMMIT, PAGE_READWRITE);
if (output == NULL)
ecl_internal_error("Unable to allocate environment structure.");
# else
output = ecl_malloc(sizeof(*output));
if (output == NULL)
ecl_internal_error("Unable to allocate environment structure.");
# endif
#endif
/* Initialize the structure with NULL data. */
ecl_mset(output, 0, sizeof(*output));
#ifdef ECL_THREADS
add_env(output);
#endif
return output;
}
void
_ecl_dealloc_env(cl_env_ptr env)
{
#ifdef ECL_THREADS
del_env(env);
#endif
#if defined(ECL_USE_MPROTECT)
if (munmap(env, sizeof(*env)))
ecl_internal_error("Unable to deallocate environment structure.");
#elif defined(ECL_USE_GUARD_PAGE)
if (!VirtualFree(env, 0, MEM_RELEASE))
ecl_internal_error("Unable to deallocate environment structure.");
#else
ecl_free_unsafe(env);
#endif
}
/* -- core runtime ---------------------------------------------------------- */
/* The root environment is a default execution context. */
static struct cl_env_struct first_env;
struct ecl_core_struct ecl_core = {
.first_env = &first_env,
/* processes */
#ifdef ECL_THREADS
.threads = ECL_NIL,
.last_var_index = 0,
.reused_indices = ECL_NIL,
#endif
/* signals */
.default_sigmask_bytes = 0,
.known_signals = ECL_NIL,
/* allocation */
.allocator = NULL,
.max_heap_size = 0,
.bytes_consed = ECL_NIL,
.gc_counter = ECL_NIL,
.gc_stats = 0,
.safety_region = NULL,
/* pathnames */
.path_max = 0,
.pathname_translations = ECL_NIL,
/* MODULES is a stack of plugins that may be loaded at boot time. */
.modules = ECL_NIL,
/* LIBRARIES is a list of objects. It behaves as a sequence of weak pointers
thanks to the magic in the garbage collector. */
.libraries = ECL_NIL,
.library_pathname = ECL_NIL
};
/* note that this function does not create any environment */
int
ecl_boot(void)
{
int i;
i = ecl_option_values[ECL_OPT_BOOTED];
if (i) {
if (i < 0) {
/* The runtime has been only suspended. Resume it.*/
ecl_set_option(ECL_OPT_BOOTED, 1);
}
return 1;
}
init_memory();
init_modules();
ecl_core.path_max = MAXPATHLEN;
return 0;
}
int
ecl_halt(void)
{
int i = ecl_option_values[ECL_OPT_BOOTED];
if (i > 0)
free_modules();
ecl_set_option(ECL_OPT_BOOTED, 0);
return 0;
}

View file

@ -68,7 +68,7 @@ si_bind_simple_restarts(cl_object tag, cl_object names)
if (ECL_FBOUNDP(@'si::bind-simple-restarts'))
return _ecl_funcall3(@'si::bind-simple-restarts', tag, names);
else
return ECL_SYM_VAL(ecl_process_env(), @'si::*restart-clusters*');
return ECL_SYM_VAL(ecl_process_env(), ECL_RESTART_CLUSTERS);
}
extern cl_object
@ -77,7 +77,7 @@ si_bind_simple_handlers(cl_object tag, cl_object names)
if (ECL_FBOUNDP(@'si::bind-simple-handlers'))
return _ecl_funcall3(@'si::bind-simple-handlers', tag, names);
else
return ECL_SYM_VAL(ecl_process_env(), @'si::*handler-clusters*');
return ECL_SYM_VAL(ecl_process_env(), ECL_SIGNAL_HANDLERS);
}
extern cl_object

View file

@ -15,6 +15,27 @@
#include <ecl/ecl.h>
#include <ecl/internal.h>
static cl_index stamp = 0;
cl_index ecl_next_stamp() {
#if ECL_THREADS
return AO_fetch_and_add((AO_t*)&stamp, 1) + 1;
#else
return ++stamp;
#endif
}
cl_object
ecl_alloc_instance(cl_index slots)
{
cl_object i;
i = ecl_alloc_object(t_instance);
i->instance.slots = (cl_object *)ecl_alloc(sizeof(cl_object) * slots);
i->instance.length = slots;
i->instance.entry = FEnot_funcallable_vararg;
i->instance.slotds = ECL_UNBOUND;
return i;
}
cl_object
ecl_allocate_instance(cl_object clas, cl_index size)
{
@ -379,7 +400,10 @@ enum ecl_built_in_classes {
ECL_BUILTIN_CODE_BLOCK,
ECL_BUILTIN_FOREIGN_DATA,
ECL_BUILTIN_FRAME,
ECL_BUILTIN_WEAK_POINTER,
ECL_BUILTIN_EXCEPTION,
ECL_BUILTIN_MODULE,
ECL_BUILTIN_WEAK_POINTER
,
ECL_BUILTIN_PROCESS,
ECL_BUILTIN_LOCK,
ECL_BUILTIN_RWLOCK,
@ -496,6 +520,10 @@ cl_class_of(cl_object x)
index = ECL_BUILTIN_FOREIGN_DATA; break;
case t_frame:
index = ECL_BUILTIN_FRAME; break;
case t_exception:
index = ECL_BUILTIN_EXCEPTION; break;
case t_module:
index = ECL_BUILTIN_MODULE; break;
case t_weak_pointer:
index = ECL_BUILTIN_WEAK_POINTER; break;
#ifdef ECL_SSE2

View file

@ -129,37 +129,6 @@ ecl_aset_bv(cl_object x, cl_index index, int value)
return value;
}
void
cl_throw(cl_object tag)
{
ecl_frame_ptr fr = frs_sch(tag);
if (fr == NULL)
FEcontrol_error("THROW: The catch ~S is undefined.", 1, tag);
ecl_unwind(ecl_process_env(), fr);
}
void
cl_return_from(cl_object block_id, cl_object block_name)
{
ecl_frame_ptr fr = frs_sch(block_id);
if (fr == NULL)
FEcontrol_error("RETURN-FROM: The block ~S with id ~S is missing.",
2, block_name, block_id);
ecl_unwind(ecl_process_env(), fr);
}
void
cl_go(cl_object tag_id, cl_object label)
{
const cl_env_ptr the_env = ecl_process_env();
ecl_frame_ptr fr = frs_sch(tag_id);
if (fr == NULL)
FEcontrol_error("GO: The tagbody ~S is missing.", 1, tag_id);
the_env->values[0] = label;
the_env->nvalues = 1;
ecl_unwind(the_env, fr);
}
cl_object
cl_grab_rest_args(ecl_va_list args)
{
@ -211,7 +180,7 @@ cl_parse_key(
}
}
/* the key is a new one */
if (keyword == @':allow-other-keys') {
if (keyword == ECL_ALLOW_OTHER_KEYS) {
if (supplied_allow_other_keys == OBJNULL)
supplied_allow_other_keys = value;
} else if (unknown_keyword == OBJNULL)
@ -224,7 +193,8 @@ cl_parse_key(
(supplied_allow_other_keys == ECL_NIL ||
supplied_allow_other_keys == OBJNULL))) {
for (i = 0; i < nkey; i++) {
if (keys[i] == @':allow-other-keys' && vars[nkey+i] == ECL_T && !Null(vars[i])) {
if (keys[i] == ECL_ALLOW_OTHER_KEYS && vars[nkey+i] == ECL_T
&& !Null(vars[i])) {
return;
}
}

View file

@ -551,7 +551,7 @@ c_macro_expand1(cl_env_ptr env, cl_object stmt)
static void
import_lexenv(cl_env_ptr env, cl_object lexenv)
{
if (!ECL_VECTORP(lexenv))
if (Null(lexenv))
return;
/*
* Given the environment of an interpreted function, we guess a
@ -3105,10 +3105,11 @@ c_cons_cdr(cl_env_ptr env, cl_object args, int flags)
cl_object
si_need_to_make_load_form_p(cl_object object)
{
cl_object load_form_cache = cl__make_hash_table(@'eq',
ecl_make_fixnum(16),
cl_core.rehash_size,
cl_core.rehash_threshold);
cl_object load_form_cache =
cl__make_hash_table(@'eq',
ecl_make_fixnum(16),
ecl_ct_default_rehash_size,
ecl_ct_default_rehash_threshold);
cl_object waiting_objects = ecl_list1(object);
cl_type type = t_start;
@ -3801,8 +3802,8 @@ init_compiler()
cl_object dispatch_table =
cl_core.compiler_dispatch =
cl__make_hash_table(@'eq', ecl_make_fixnum(128), /* size */
cl_core.rehash_size,
cl_core.rehash_threshold);
ecl_ct_default_rehash_size,
ecl_ct_default_rehash_threshold);
int i;
for (i = 0; database[i].symbol; i++) {
ecl_sethash(database[i].symbol, dispatch_table, ecl_make_fixnum(i));

View file

@ -204,12 +204,19 @@ disassemble(cl_object bytecodes, cl_opcode *vector) {
goto OPARG;
/* OP_QUOTE
Sets VALUES(0) to an immediate value.
Sets REG0 to an immediate value.
*/
case OP_QUOTE: string = "QUOTE\t";
GET_DATA(o, vector, data);
goto ARG;
/* OP_CALLW
Sets REG0 to a result of calling an immediate value.
*/
case OP_CALLW: string = "CALLW\t";
GET_DATA(o, vector, data);
goto ARG;
/* OP_CSET n{arg}
Replace constant with a computed value
*/

View file

@ -753,7 +753,7 @@ put_declaration(void)
if (nopt == 0 && !rest_flag && !key_flag) {
put_lineno();
fprintf(out, "\tif (ecl_unlikely(narg!=%d))", nreq);
fprintf(out, "\t FEwrong_num_arguments(ecl_make_fixnum(%d));\n",
fprintf(out, "\t ecl_ferror2(ECL_EX_F_NARGS, ecl_make_fixnum(%d));\n",
function_code);
} else {
simple_varargs = !rest_flag && !key_flag && ((nreq + nopt) < 32);
@ -782,7 +782,7 @@ put_declaration(void)
if (nopt > 0 && !rest_flag && !key_flag) {
fprintf(out, "|| narg > %d", nreq + nopt);
}
fprintf(out, ")) FEwrong_num_arguments(ecl_make_fixnum(%d));\n", function_code);
fprintf(out, ")) ecl_ferror2(ECL_EX_F_NARGS, ecl_make_fixnum(%d));\n", function_code);
for (i = 0; i < nopt; i++) {
put_lineno();
fprintf(out, "\tif (narg > %d) {\n", nreq+i);

100
src/c/eql.d Normal file
View file

@ -0,0 +1,100 @@
/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* vim: set filetype=c tabstop=2 shiftwidth=2 expandtab: */
/* aux.c - early routines */
/* -- imports --------------------------------------------------------------- */
#include <ecl/ecl.h>
#include <ecl/ecl-inl.h>
#include <ecl/internal.h>
#include <ecl/external.h>
#include <string.h>
/*
* EQL-comparison of floats. If we are using signed zeros and NaNs,
* numeric comparison of floating points is not equivalent to bit-wise
* equality. In particular every two NaNs always give false
* (= #1=(/ 0.0 0.0) #1#) => NIL
* and signed zeros always compare equal
* (= 0 -0.0) => T
* which is not the same as what EQL should return
* (EQL #1=(/ 0.0 0.0) #1#) => T
* (EQL 0 -0.0) => NIL
*
* Furthermore, we can not use bit comparisons because in some platforms
* long double has unused bits that makes two long floats be = but not eql.
*/
#if !defined(ECL_SIGNED_ZERO) && !defined(ECL_IEEE_FP)
#define FLOAT_EQL(name, type) \
static bool name(type a, type b) { return a == b; }
#else
#define FLOAT_EQL(name, type) \
static bool name(type a, type b) { \
if (a == b) return signbit(a) == signbit(b); \
if (isnan(a) || isnan(b)) return isnan(a) && isnan(b); \
return 0; \
}
#endif
FLOAT_EQL(float_eql, float);
FLOAT_EQL(double_eql, double);
FLOAT_EQL(long_double_eql, long double);
#undef FLOAT_EQL
/* To avoid linking GMP in nucleus we directly compare limbs. */
static bool
_bignum_eql(cl_object x, cl_object y)
{
cl_fixnum size;
size = ECL_BIGNUM_SIZE(x);
if(size != ECL_BIGNUM_SIZE(y)) return 0;
return !memcmp(ECL_BIGNUM_LIMBS(x),
ECL_BIGNUM_LIMBS(y),
size * (ECL_BIGNUM_LIMB_BITS/8));
}
bool
ecl_eql(cl_object x, cl_object y)
{
if (x == y)
return TRUE;
if (ECL_IMMEDIATE(x) || ECL_IMMEDIATE(y))
return FALSE;
if (x->d.t != y->d.t)
return FALSE;
switch (x->d.t) {
case t_bignum:
return _bignum_eql(x, y);
case t_ratio:
return (ecl_eql(x->ratio.num, y->ratio.num) &&
ecl_eql(x->ratio.den, y->ratio.den));
case t_singlefloat:
return float_eql(ecl_single_float(x), ecl_single_float(y));
case t_longfloat:
return long_double_eql(ecl_long_float(x), ecl_long_float(y));
case t_doublefloat:
return double_eql(ecl_double_float(x), ecl_double_float(y));
case t_complex:
return (ecl_eql(x->gencomplex.real, y->gencomplex.real) &&
ecl_eql(x->gencomplex.imag, y->gencomplex.imag));
#ifdef ECL_COMPLEX_FLOAT
case t_csfloat:
return (float_eql(crealf(ecl_csfloat(x)), crealf(ecl_csfloat(y))) &&
float_eql(cimagf(ecl_csfloat(x)), cimagf(ecl_csfloat(y))));
case t_cdfloat:
return (double_eql(creal(ecl_cdfloat(x)), creal(ecl_cdfloat(y))) &&
double_eql(cimag(ecl_cdfloat(x)), cimag(ecl_cdfloat(y))));
case t_clfloat:
return (long_double_eql(creall(ecl_clfloat(x)), creall(ecl_clfloat(y))) &&
long_double_eql(cimagl(ecl_clfloat(x)), cimagl(ecl_clfloat(y))));
#endif
#ifdef ECL_SSE2
case t_sse_pack:
return !memcmp(x->sse.data.b8, y->sse.data.b8, 16);
#endif
default:
return FALSE;
}
}

View file

@ -24,69 +24,12 @@
#include <ecl/internal.h>
#include <ecl/ecl-inl.h>
static cl_object
cl_symbol_or_object(cl_object x)
{
if (ECL_FIXNUMP(x))
return (cl_object)(cl_symbols + ecl_fixnum(x));
return x;
}
void
_ecl_unexpected_return()
{
ecl_internal_error(
"*** \n"
"*** A call to ERROR returned without handling the error.\n"
"*** This should have never happened and is usually a signal\n"
"*** that the debugger or the universal error handler were\n"
"*** improperly coded or altered. Please contact the maintainers\n"
"***\n");
}
void
ecl_internal_error(const char *s)
{
int saved_errno = errno;
fprintf(stderr, "\nInternal or unrecoverable error in:\n%s\n", s);
if (saved_errno) {
fprintf(stderr, " [%d: %s]\n", saved_errno, strerror(saved_errno));
}
fflush(stderr);
_ecl_dump_c_backtrace();
#ifdef SIGIOT
signal(SIGIOT, SIG_DFL); /* avoid getting into a loop with abort */
#endif
abort();
}
#ifdef ECL_THREADS
void
ecl_thread_internal_error(const char *s)
{
int saved_errno = errno;
fprintf(stderr, "\nInternal thread error in:\n%s\n", s);
if (saved_errno) {
fprintf(stderr, " [%d: %s]\n", saved_errno, strerror(saved_errno));
}
_ecl_dump_c_backtrace();
fprintf(stderr,
"\nDid you forget to call `ecl_import_current_thread'?\n"
"Exitting thread.\n");
fflush(stderr);
ecl_thread_exit();
}
#endif
void
ecl_unrecoverable_error(cl_env_ptr the_env, const char *message)
{
/*
* Right now we have no means of specifying a jump point
* for really bad events. We just jump to the outermost
* frame, which is equivalent to quitting, and wait for
* someone to intercept this jump.
*/
/* Right now we have no means of specifying a jump point for really bad
* events. We just jump to the outermost frame, which is equivalent to
* quitting, and wait for someone to intercept this jump. */
ecl_frame_ptr destination;
cl_object tag;
@ -112,21 +55,139 @@ ecl_unrecoverable_error(cl_env_ptr the_env, const char *message)
}
}
void
ecl_miscompilation_error()
/* -- Integration with low-level exceptions */
cl_object
ecl_exception_handler(cl_object o)
{
ecl_internal_error(
"***\n"
"*** Encountered a code path that should have never been taken.\n"
"*** This likely indicates a bug in the ECL compiler. Please contact\n"
"*** the maintainers.\n"
"***\n");
if (ECL_EXCEPTIONP(o)) {
cl_object arg1 = o->exception.arg1;
cl_object arg2 = o->exception.arg2;
cl_object arg3 = o->exception.arg3;
cl_object hand = @'si::universal-error-handler';
switch (o->exception.ex_type) {
/* General conditions */
case ECL_EX_FERROR:
ecl_enable_interrupts();
return _ecl_funcall4(hand, ECL_NIL, arg1, arg2);
case ECL_EX_CERROR:
ecl_enable_interrupts();
return _ecl_funcall4(hand, ECL_T, arg1, arg2);
/* Specific conditions */
case ECL_EX_BADARG:
FEwrong_type_argument(arg1, arg2);
break;
case ECL_EX_BADARG_ONLY:
FEwrong_type_only_arg(arg1, arg2, arg3);
break;
case ECL_EX_UNSATISFIED:
FEwrong_type_pred_arg(arg1, arg2);
break;
case ECL_EX_STRM_BADELT:
FEwrong_type_strm_elt(arg1, arg2);
break;
case ECL_EX_STRM_CLOSED:
FEclosed_stream(arg1);
break;
case ECL_EX_STRM_UNREAD:
FEunread_stream(arg1, arg2);
break;
case ECL_EX_EOF:
FEend_of_file(arg1);
break;
case ECL_EX_NIY:
FEerror("The operation is not implemented yet.", 0);
break;
case ECL_EX_NAO:
FEerror("The operation is not applicable to ~A.", 1, arg1);
break;
/* Stack conditions */
case ECL_EX_CS_OVR:
CEstack_overflow(@'ext::c-stack', arg1, arg2);
break;
case ECL_EX_FRS_OVR:
CEstack_overflow(@'ext::frame-stack', arg1, arg2);
break;
case ECL_EX_BDS_OVR:
CEstack_overflow(@'ext::binding-stack', arg1, arg2);
break;
/* KLUDGE ByteVM-specific conditions */
case ECL_EX_VM_BADARG_EXCD:
FEprogram_error("Too many arguments passed to function ~A~&"
"Argument list: ~S",
2, arg1, cl_apply(2, @'list', arg2));
break;
case ECL_EX_VM_BADARG_UNKK:
FEprogram_error("Unknown keyword argument passed to function ~A.~&"
"Argument list: ~S",
2, arg1, cl_apply(2, @'list', arg2));
break;
case ECL_EX_VM_BADARG_ODDK:
FEprogram_error("Odd number of keyword arguments passed to function ~A.~&"
"Argument list: ~S",
2, arg1, cl_apply(2, @'list', arg2));
break;
case ECL_EX_VM_BADARG_NTH_VAL:
FEerror("Wrong index passed to NTH-VAL", 0);
break;
case ECL_EX_VM_BADARG_ENDP:
FEwrong_type_only_arg(@[endp], arg1, @[list]);
break;
case ECL_EX_VM_BADARG_CAR:
FEwrong_type_only_arg(@[car], arg1, @[list]);
break;
case ECL_EX_VM_BADARG_CDR:
FEwrong_type_only_arg(@[cdr], arg1, @[list]);
break;
case ECL_EX_VM_BADARG_PROGV:
FEerror("Wrong arguments to special form PROGV. Either~%"
"~A~%or~%~A~%are not proper lists",
2, arg1, arg2);
break;
/* Variable conditions */
case ECL_EX_V_CSETQ:
FEassignment_to_constant(arg1);
break;
case ECL_EX_V_CBIND:
FEbinding_a_constant(arg1);
break;
case ECL_EX_V_UNBND:
FEunbound_variable(arg1);
break;
case ECL_EX_V_BNAME:
FEunbound_variable(arg1);
break;
/* Function conditions */
case ECL_EX_F_NARGS:
FEwrong_num_arguments(arg1);
break;
case ECL_EX_F_UNDEF:
FEundefined_function(arg1);
break;
case ECL_EX_F_INVAL:
FEinvalid_function(arg1);
break;
case ECL_EX_S_FMISS:
FEcontrol_error("UNWIND: frame ~s not found.", 1, arg1);
break;
default:
ecl_internal_error("Unknown exception type.");
}
}
return ECL_NIL;
}
/*****************************************************************************/
/* Support for Lisp Error Handler */
/*****************************************************************************/
static cl_object
cl_symbol_or_object(cl_object x)
{
if (ECL_FIXNUMP(x))
return (cl_object)(cl_symbols + ecl_fixnum(x));
return x;
}
void
FEerror(const char *s, int narg, ...)
{
@ -241,7 +302,7 @@ FEreader_error(const char *s, cl_object stream, int narg, ...)
} else {
/* Actual reader error */
cl_object prefix = @"Reader error in file ~S, position ~D:~%";
cl_object position = cl_file_position(1, stream);
cl_object position = ecl_file_position(stream);
message = si_base_string_concatenate(2, prefix, message);
args_list = cl_listX(3, stream, position, args_list);
si_signal_simple_error(6,
@ -281,6 +342,16 @@ FEclosed_stream(cl_object strm)
cl_error(3, @'stream-error', @':stream', strm);
}
void
FEunread_stream(cl_object strm, cl_object twice)
{
if(Null(twice)) {
FEerror("Error when using UNREAD-CHAR on stream ~D", 1, strm);
} else {
FEerror("Used UNREAD-CHAR twice on stream ~D", 1, strm);
}
}
cl_object
si_signal_type_error(cl_object value, cl_object type)
{
@ -294,6 +365,25 @@ FEwrong_type_argument(cl_object type, cl_object value)
si_signal_type_error(value, cl_symbol_or_object(type));
}
void
FEwrong_type_pred_arg(cl_object type, cl_object value)
{
cl_object predicate = cl_symbol_or_object(type);
cl_object expected = cl_list(2, @'satisfies', predicate);
si_signal_type_error(value, expected);
}
void
FEwrong_type_strm_elt(cl_object type, cl_object value)
{
cl_object expected = cl_symbol_or_object(type);
cl_error(9, @'simple-type-error', @':format-control',
@"~A stream element type is not ~S.",
@':format-arguments', cl_list(2, value, expected),
@':expected-type', expected,
@':datum', cl_stream_element_type(value));
}
void
FEwrong_type_only_arg(cl_object function, cl_object value, cl_object type)
{
@ -306,7 +396,7 @@ FEwrong_type_only_arg(cl_object function, cl_object value, cl_object type)
function = cl_symbol_or_object(function);
type = cl_symbol_or_object(type);
if (!Null(function) && env->ihs_stack.top && env->ihs_stack.top->function != function) {
ecl_ihs_push(env,&tmp_ihs,function,ECL_NIL);
ecl_ihs_push(env,&tmp_ihs,function,ECL_NIL,ECL_NIL);
}
si_signal_simple_error(8,
@'type-error', /* condition name */
@ -330,7 +420,7 @@ FEwrong_type_nth_arg(cl_object function, cl_narg narg, cl_object value, cl_objec
function = cl_symbol_or_object(function);
type = cl_symbol_or_object(type);
if (!Null(function) && env->ihs_stack.top && env->ihs_stack.top->function != function) {
ecl_ihs_push(env,&tmp_ihs,function,ECL_NIL);
ecl_ihs_push(env,&tmp_ihs,function,ECL_NIL,ECL_NIL);
}
si_signal_simple_error(8,
@'type-error', /* condition name */
@ -356,7 +446,7 @@ FEwrong_type_key_arg(cl_object function, cl_object key, cl_object value, cl_obje
type = cl_symbol_or_object(type);
key = cl_symbol_or_object(key);
if (!Null(function) && env->ihs_stack.top && env->ihs_stack.top->function != function) {
ecl_ihs_push(env,&tmp_ihs,function,ECL_NIL);
ecl_ihs_push(env,&tmp_ihs,function,ECL_NIL,ECL_NIL);
}
si_signal_simple_error(8,
@'type-error', /* condition name */
@ -387,7 +477,7 @@ FEwrong_index(cl_object function, cl_object a, int which, cl_object ndx,
struct ecl_ihs_frame tmp_ihs;
function = cl_symbol_or_object(function);
if (!Null(function) && env->ihs_stack.top && env->ihs_stack.top->function != function) {
ecl_ihs_push(env,&tmp_ihs,function,ECL_NIL);
ecl_ihs_push(env,&tmp_ihs,function,ECL_NIL,ECL_NIL);
}
cl_error(9,
@'simple-type-error', /* condition name */
@ -622,6 +712,5 @@ void
init_error(void)
{
ecl_def_c_function(@'si::universal-error-handler',
(cl_objectfn_fixed)universal_error_handler,
3);
(cl_objectfn_fixed)universal_error_handler, 3);
}

293
src/c/escape.d Normal file
View file

@ -0,0 +1,293 @@
/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* vim: set filetype=c tabstop=2 shiftwidth=2 expandtab: */
/* control.c - signaling conditions and transfering program control */
#include <ecl/ecl.h>
#include <ecl/ecl-inl.h>
#include <ecl/internal.h>
#include <ecl/external.h>
#include <ecl/nucleus.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#if defined(ECL_MS_WINDOWS_HOST) || defined(cygwin)
# include <windows.h>
#endif
#if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS)
# include <execinfo.h>
# define ECL_UNIX_BACKTRACE
#endif
#if defined(ECL_WINDOWS_BACKTRACE)
# include <windows.h>
# include <DbgHelp.h>
#endif
/* -- Escapes --------------------------------------------------------------- **
Non-local transfer of control. Practically this is like THROW, where
continuation is the exit point estabilished by an equivalent of CATCH.
** -------------------------------------------------------------------------- */
void
ecl_escape(cl_object continuation)
{
ecl_frame_ptr fr = frs_sch(continuation);
if (!fr) {
ecl_ferror(ECL_EX_S_FMISS, continuation, ECL_NIL);
}
ecl_unwind(ecl_process_env(), fr);
_ecl_unexpected_return();
}
void
ecl_unwind(cl_env_ptr env, ecl_frame_ptr fr)
{
env->frs_stack.nlj_fr = fr;
ecl_frame_ptr top = env->frs_stack.top;
while (top != fr && top->frs_val != ECL_PROTECT_TAG){
top->frs_val = ECL_DUMMY_TAG;
--top;
}
env->ihs_stack.top = top->frs_ihs;
ecl_bds_unwind(env, top->frs_bds_ndx);
ECL_STACK_UNWIND(env, top->frs_run_ndx);
env->frs_stack.top = top;
ecl_longjmp(env->frs_stack.top->frs_jmpbuf, 1);
/* never reached */
}
void
cl_throw(cl_object tag)
{
ecl_escape(tag);
}
void
cl_return_from(cl_object block_id, cl_object block_name)
{
ecl_escape(block_id);
}
void
cl_go(cl_object tag_id, cl_object label)
{
const cl_env_ptr the_env = ecl_process_env();
the_env->values[0] = label;
the_env->nvalues = 1;
ecl_escape(tag_id);
}
/* -- Signaling conditions -------------------------------------------------- **
Low level signals work slightly different from Common Lisp. There are no handler
clusters nor restarts. %signal is called with three arguments:
- condition :: the signaled object (may be any cl_object)
- returns :: the flag stating whether whether the function returns
- destination :: the thread the condition is delivered to (implementme!)
The signal invokes all handlers bound with with-handler in LIFO order and call
them with the condition. The handler may take do one of the following:
- decline :: return, then signal proceeds to the next handler
- escape :: perform non-local transfer of control
- defer :: signal a condition, invoke a debugger, ...
The called handler is not bound as an active signal handler during its execution
to avoid an infinite recursion while resignaling. When all handlers decline and
the CONTINUABLE is ECL_NIL, then we abort the program by invoking the function
_ecl_unexpected_return().
** -------------------------------------------------------------------------- */
cl_object
ecl_signal(cl_object condition, cl_object returns, cl_object thread) {
const cl_env_ptr the_env = ecl_process_env();
cl_object symbol, cluster, handler;
symbol = ECL_SIGNAL_HANDLERS;
cluster = ECL_SYM_VAL(the_env, symbol);
ecl_bds_bind(the_env, symbol, cluster);
while(!Null(cluster)) {
handler = ECL_CONS_CAR(cluster);
cluster = ECL_CONS_CDR(cluster);
ECL_SETQ(the_env, symbol, cluster);
_ecl_funcall2(handler, condition);
}
if (returns == ECL_NIL)
_ecl_unexpected_return();
ecl_bds_unwind1(the_env);
return ECL_NIL;
}
cl_object
ecl_call_with_handler(cl_object handler, cl_object continuation)
{
cl_env_ptr the_env = ecl_process_env();
cl_object result;
ECL_WITH_HANDLER_BEGIN(the_env, handler) {
result = _ecl_funcall1(continuation);
} ECL_WITH_HANDLER_END;
return result;
}
/* -- Exceptions ------------------------------------------------------------ **
Conditions in Common Lisp are instances of STANDARD-CLASS. While eventually I'd
like to include classes to the early environment, that would be too much work at
one go. This is also the reason why ecl_signal accepts all kinds of objects.
In order to signal conditions in the early environment we use a trick: we pass
to ecl_signal objects of type ecl_exception that are recognized by a Common Lisp
handler, and that handler resignals proper conditions. Exceptions are allocated
on the stack and capturing them is prohibited.
ecl_raise is very similar to ecl_signal with an exception that it does not pop
the current handler from the stack. This is to ensure, that the condition
handler is invoked despite being "above" the exception handler on the stack. To
avoid infinite recursion it is prohibited to resignal the exception itself.
** ---------------------------------------------------------------------------*/
cl_object
ecl_raise(ecl_ex_type type, bool returns,
cl_object arg1, cl_object arg2, cl_object arg3, void *arg4)
{
const cl_env_ptr the_env = ecl_process_env();
struct ecl_exception ex =
{ .t = t_exception, .ex_type = type,
.arg1 = arg1, .arg2 = arg2, .arg3 = arg3, .arg4 = arg4 };
cl_object symbol, cluster, handler;
cl_object exception = ecl_cast_ptr(cl_object,&ex);
symbol = ECL_SIGNAL_HANDLERS;
cluster = ECL_SYM_VAL(the_env, symbol);
ecl_bds_bind(the_env, symbol, cluster);
while(!Null(cluster)) {
handler = ECL_CONS_CAR(cluster);
cluster = ECL_CONS_CDR(cluster);
_ecl_funcall2(handler, exception);
}
if (!returns)
_ecl_unexpected_return();
ecl_bds_unwind1(the_env);
return ECL_NIL;
}
/* -- Fatal errors ---------------------------------------------------------- **
Fatal errors that can't be recovered from and result in the program abortion.
** ---------------------------------------------------------------------------*/
void
ecl_internal_error(const char *s)
{
int saved_errno = errno;
fprintf(stderr, "\nInternal or unrecoverable error in:\n%s\n", s);
if (saved_errno) {
fprintf(stderr, " [%d: %s]\n", saved_errno, strerror(saved_errno));
}
fflush(stderr);
_ecl_dump_c_backtrace();
#ifdef SIGIOT
signal(SIGIOT, SIG_DFL); /* avoid getting into a loop with abort */
#endif
abort();
}
#ifdef ECL_THREADS
void
ecl_thread_internal_error(const char *s)
{
int saved_errno = errno;
fprintf(stderr, "\nInternal thread error in:\n%s\n", s);
if (saved_errno) {
fprintf(stderr, " [%d: %s]\n", saved_errno, strerror(saved_errno));
}
_ecl_dump_c_backtrace();
fprintf(stderr, "\nDid you forget to call `ecl_import_current_thread'?\n"
"Exitting thread.\n");
fflush(stderr);
ecl_thread_exit();
_ecl_unexpected_return();
}
#endif
void
_ecl_unexpected_return()
{
ecl_internal_error("*** \n"
"*** A call to ERROR returned without handling the error.\n"
"*** This should have never happened and is usually a signal\n"
"*** that the debugger or the universal error handler were\n"
"*** improperly coded or altered. Please contact the maintainers\n"
"*** \n");
}
void
ecl_miscompilation_error()
{
ecl_internal_error("*** \n"
"*** Encountered a code path that should have never been taken.\n"
"*** This likely indicates a bug in the ECL compiler. Please contact\n"
"*** the maintainers.\n"
"*** \n");
}
/* Max number of frames dumped by _ecl_dump_c_backtrace */
#define MAX_BACKTRACE_SIZE 128
/* Max length of symbols printed */
#define MAX_SYMBOL_LENGTH 256
void
_ecl_dump_c_backtrace()
{
#if defined(ECL_UNIX_BACKTRACE) || defined(ECL_WINDOWS_BACKTRACE)
{
void **pointers = malloc(sizeof(void*) * MAX_BACKTRACE_SIZE);
# if defined(ECL_UNIX_BACKTRACE)
int nframes = backtrace(pointers, MAX_BACKTRACE_SIZE);
char **names = backtrace_symbols(pointers, nframes);
# elif defined(ECL_WINDOWS_BACKTRACE)
HANDLE process = GetCurrentProcess();
if (!SymInitialize(process, NULL, TRUE)) {
return;
}
int nframes = CaptureStackBackTrace(0, MAX_BACKTRACE_SIZE, pointers, NULL);
char buffer[sizeof(SYMBOL_INFO) + MAX_SYMBOL_LENGTH * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYMBOL_LENGTH;
# endif
int i;
fprintf(stderr, "\n;;; ECL C Backtrace\n");
for (i = 0; i < nframes; i++) {
# if defined(ECL_UNIX_BACKTRACE)
fprintf(stderr, ";;; %s\n", names[i]);
# elif defined(ECL_WINDOWS_BACKTRACE)
DWORD64 displacement;
if (SymFromAddr(process, (DWORD64) pointers[i], &displacement, pSymbol)) {
fprintf(stderr, ";;; (%s+0x%llx) [0x%p]\n", pSymbol->Name, displacement, pointers[i]);
} else {
fprintf(stderr, ";;; (unknown) [0x%p]\n", pointers[i]);
}
# endif
}
fflush(stderr);
ecl_free(pointers);
# if defined(ECL_UNIX_BACKTRACE)
ecl_free(names);
# elif defined(ECL_WINDOWS_BACKTRACE)
SymCleanup(process);
# endif
}
#endif /* defined(ECL_UNIX_BACKTRACE) || defined(ECL_WINDOWS_BACKTRACE) */
}

View file

@ -16,127 +16,6 @@
#include <ecl/ecl-inl.h>
#include <ecl/internal.h>
cl_object *
_ecl_va_sp(cl_narg narg)
{
return ECL_STACK_FRAME_PTR(ecl_process_env()->stack_frame) + narg;
}
/* Calling conventions:
* Compiled C code calls lisp function supplying #args, and args.
* Linking function performs check_args, gets jmp_buf with _setjmp, then
* if cfun then stores C code address into function link location
* and transfers to jmp_buf at cf_self
* if cclosure then replaces #args with cc_env and calls cc_self
* otherwise, it emulates funcall.
*/
cl_object
ecl_apply_from_stack_frame(cl_object frame, cl_object x)
{
cl_object *sp = ECL_STACK_FRAME_PTR(frame);
cl_index narg = frame->frame.size;
cl_object fun = x;
cl_object ret;
frame->frame.env->stack_frame = frame;
AGAIN:
frame->frame.env->function = fun;
if (ecl_unlikely(fun == ECL_NIL))
FEundefined_function(x);
switch (ecl_t_of(fun)) {
case t_cfunfixed:
if (ecl_unlikely(narg != (cl_index)fun->cfun.narg))
FEwrong_num_arguments(fun);
ret = APPLY_fixed(narg, fun->cfunfixed.entry_fixed, sp);
break;
case t_cfun:
ret = APPLY(narg, fun->cfun.entry, sp);
break;
case t_cclosure:
ret = APPLY(narg, fun->cclosure.entry, sp);
break;
case t_instance:
switch (fun->instance.isgf) {
case ECL_STANDARD_DISPATCH:
case ECL_RESTRICTED_DISPATCH:
ret = _ecl_standard_dispatch(frame, fun);
break;
case ECL_USER_DISPATCH:
fun = fun->instance.slots[fun->instance.length - 1];
goto AGAIN;
case ECL_READER_DISPATCH:
case ECL_WRITER_DISPATCH:
ret = APPLY(narg, fun->instance.entry, sp);
break;
default:
FEinvalid_function(fun);
}
break;
case t_symbol:
if (ecl_unlikely(!ECL_FBOUNDP(fun)))
FEundefined_function(fun);
fun = ECL_SYM_FUN(fun);
goto AGAIN;
case t_bytecodes:
ret = ecl_interpret(frame, ECL_NIL, fun);
break;
case t_bclosure:
ret = ecl_interpret(frame, fun->bclosure.lex, fun->bclosure.code);
break;
default:
FEinvalid_function(x);
}
frame->frame.env->stack_frame = NULL; /* for gc's sake */
return ret;
}
cl_objectfn
ecl_function_dispatch(cl_env_ptr env, cl_object x)
{
cl_object fun = x;
if (ecl_unlikely(fun == ECL_NIL))
FEundefined_function(x);
switch (ecl_t_of(fun)) {
case t_cfunfixed:
env->function = fun;
return fun->cfunfixed.entry;
case t_cfun:
env->function = fun;
return fun->cfun.entry;
case t_cclosure:
env->function = fun;
return fun->cclosure.entry;
case t_instance:
env->function = fun;
return fun->instance.entry;
case t_symbol:
fun = ECL_SYM_FUN(fun);
env->function = fun;
return fun->cfun.entry;
case t_bytecodes:
env->function = fun;
return fun->bytecodes.entry;
case t_bclosure:
env->function = fun;
return fun->bclosure.entry;
default:
FEinvalid_function(x);
}
}
cl_object
cl_funcall(cl_narg narg, cl_object function, ...)
{
cl_object output;
--narg;
{
ECL_STACK_FRAME_VARARGS_BEGIN(narg, function, frame);
output = ecl_apply_from_stack_frame(frame, function);
ECL_STACK_FRAME_VARARGS_END(frame);
}
return output;
}
@(defun apply (fun lastarg &rest args)
@ {
if (narg == 2 && ecl_t_of(lastarg) == t_frame) {

View file

@ -13,6 +13,7 @@
#include <string.h>
#define ECL_INCLUDE_FFI_H
#include <ecl/ecl.h>
#include <ecl/ecl-inl.h>
#include <ecl/internal.h>
static const cl_object ecl_aet_to_ffi_table[ecl_aet_bc+1] = {
@ -312,7 +313,7 @@ si_allocate_foreign_data(cl_object tag, cl_object size)
/* FIXME! Should be atomic uncollectable or malloc, but we do not export
* that garbage collector interface and malloc may be overwritten
* by the GC library */
output->foreign.data = bytes? ecl_alloc_uncollectable(bytes) : NULL;
output->foreign.data = bytes? ecl_alloc_manual(bytes) : NULL;
@(return output);
}
@ -325,7 +326,7 @@ si_free_foreign_data(cl_object f)
}
if (f->foreign.size) {
/* See si_allocate_foreign_data() */
ecl_free_uncollectable(f->foreign.data);
ecl_free(f->foreign.data);
}
f->foreign.size = 0;
f->foreign.data = NULL;
@ -1019,3 +1020,32 @@ si_free_ffi_closure(cl_object closure)
@(return closure_object);
} @)
#endif /* HAVE_LIBFFI */
/* -- Module definition ------------------------------------------------------ */
static cl_object
init_env_ffi(cl_env_ptr the_env)
{
#ifdef HAVE_LIBFFI
the_env->ffi_args_limit = 0;
the_env->ffi_types = 0;
the_env->ffi_values = 0;
the_env->ffi_values_ptrs = 0;
#endif
return ECL_NIL;
}
ecl_def_ct_base_string(str_ffi, "FFI", 3, static, const);
static struct ecl_module module_ffi = {
.name = str_ffi,
.create = ecl_module_no_op,
.enable = ecl_module_no_op,
.init_env = init_env_ffi,
.init_cpu = ecl_module_no_op_cpu,
.free_cpu = ecl_module_no_op_cpu,
.free_env = ecl_module_no_op_env,
.disable = ecl_module_no_op,
.destroy = ecl_module_no_op
};
cl_object ecl_module_ffi = (cl_object)&module_ffi;

View file

@ -24,56 +24,9 @@
# include <DbgHelp.h>
#endif
/* Max number of frames dumped by _ecl_dump_c_backtrace */
#define MAX_BACKTRACE_SIZE 128
/* Max length of symbols printed */
#define MAX_SYMBOL_LENGTH 256
void
_ecl_dump_c_backtrace()
{
#if defined(ECL_UNIX_BACKTRACE) || defined(ECL_WINDOWS_BACKTRACE)
{
void **pointers = malloc(sizeof(void*) * MAX_BACKTRACE_SIZE);
# if defined(ECL_UNIX_BACKTRACE)
int nframes = backtrace(pointers, MAX_BACKTRACE_SIZE);
char **names = backtrace_symbols(pointers, nframes);
# elif defined(ECL_WINDOWS_BACKTRACE)
HANDLE process = GetCurrentProcess();
if (!SymInitialize(process, NULL, TRUE)) {
return;
}
int nframes = CaptureStackBackTrace(0, MAX_BACKTRACE_SIZE, pointers, NULL);
char buffer[sizeof(SYMBOL_INFO) + MAX_SYMBOL_LENGTH * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYMBOL_LENGTH;
# endif
int i;
fprintf(stderr, "\n;;; ECL C Backtrace\n");
for (i = 0; i < nframes; i++) {
# if defined(ECL_UNIX_BACKTRACE)
fprintf(stderr, ";;; %s\n", names[i]);
# elif defined(ECL_WINDOWS_BACKTRACE)
DWORD64 displacement;
if (SymFromAddr(process, (DWORD64) pointers[i], &displacement, pSymbol)) {
fprintf(stderr, ";;; (%s+0x%llx) [0x%p]\n", pSymbol->Name, displacement, pointers[i]);
} else {
fprintf(stderr, ";;; (unknown) [0x%p]\n", pointers[i]);
}
# endif
}
fflush(stderr);
free(pointers);
# if defined(ECL_UNIX_BACKTRACE)
free(names);
# elif defined(ECL_WINDOWS_BACKTRACE)
SymCleanup(process);
# endif
}
#endif /* defined(ECL_UNIX_BACKTRACE) || defined(ECL_WINDOWS_BACKTRACE) */
}
cl_object
si_dump_c_backtrace(cl_object size)
{

View file

@ -221,7 +221,7 @@ static cl_object
ecl_library_find_by_name(cl_object filename)
{
cl_object l;
for (l = cl_core.libraries; l != ECL_NIL; l = ECL_CONS_CDR(l)) {
for (l = ecl_core.libraries; l != ECL_NIL; l = ECL_CONS_CDR(l)) {
cl_object other = ECL_CONS_CAR(l);
cl_object name = other->cblock.name;
if (!Null(name) && ecl_string_eq(name, filename)) {
@ -235,7 +235,7 @@ static cl_object
ecl_library_find_by_handle(void *handle)
{
cl_object l;
for (l = cl_core.libraries; l != ECL_NIL; l = ECL_CONS_CDR(l)) {
for (l = ecl_core.libraries; l != ECL_NIL; l = ECL_CONS_CDR(l)) {
cl_object other = ECL_CONS_CAR(l);
if (handle == other->cblock.handle) {
return other;
@ -268,7 +268,7 @@ ecl_library_open_inner(cl_object filename, bool self_destruct)
block->cblock.refs = ecl_one_plus(block->cblock.refs);
} else {
si_set_finalizer(block, ECL_T);
cl_core.libraries = CONS(block, cl_core.libraries);
ecl_core.libraries = CONS(block, ecl_core.libraries);
}
}
ecl_enable_interrupts();
@ -341,7 +341,7 @@ ecl_library_symbol(cl_object block, const char *symbol, bool lock) {
void *p;
if (block == @':default') {
cl_object l;
for (l = cl_core.libraries; l != ECL_NIL; l = ECL_CONS_CDR(l)) {
for (l = ecl_core.libraries; l != ECL_NIL; l = ECL_CONS_CDR(l)) {
cl_object block = ECL_CONS_CAR(l);
p = ecl_library_symbol(block, symbol, lock);
if (p) return p;
@ -426,7 +426,7 @@ ecl_library_close(cl_object block) {
block = ECL_NIL;
} else if (block->cblock.handle != NULL) {
success = GC_call_with_alloc_lock(dlclose_wrapper, block);
cl_core.libraries = ecl_remove_eq(block, cl_core.libraries);
ecl_core.libraries = ecl_remove_eq(block, ecl_core.libraries);
} else { /* block not loaded */
success = FALSE;
}
@ -443,8 +443,8 @@ ecl_library_close(cl_object block) {
void
ecl_library_close_all(void)
{
while (cl_core.libraries != ECL_NIL) {
ecl_library_close(ECL_CONS_CAR(cl_core.libraries));
while (ecl_core.libraries != ECL_NIL) {
ecl_library_close(ECL_CONS_CAR(ecl_core.libraries));
}
}

View file

@ -151,3 +151,45 @@ ecl_normalize_stream_element_type(cl_object element_type)
@
@(return ecl_stream_dispatch_table(strm)->close(strm));
@)
cl_object
si_file_stream_fd(cl_object s)
{
cl_object ret;
unlikely_if (!ECL_FILE_STREAM_P(s)) {
ecl_not_a_file_stream(s);
}
switch ((enum ecl_smmode)s->stream.mode) {
case ecl_smm_input:
case ecl_smm_output:
case ecl_smm_io:
ret = ecl_make_fixnum(fileno(IO_STREAM_FILE(s)));
break;
case ecl_smm_input_file:
case ecl_smm_output_file:
case ecl_smm_io_file:
ret = ecl_make_fixnum(IO_FILE_DESCRIPTOR(s));
break;
default:
ecl_internal_error("not a file stream");
}
@(return ret);
}
@(defun file-position (file_stream &o position)
cl_object output;
@
if (Null(position)) {
output = ecl_file_position(file_stream);
} else {
if (position == @':start') {
position = ecl_make_fixnum(0);
} else if (position == @':end') {
position = ECL_NIL;
}
output = ecl_file_position_set(file_stream, position);
}
@(return output);
@)

View file

@ -943,8 +943,8 @@ ecl_extend_hashtable(cl_object hashtable)
(weakness ECL_NIL)
(synchronized ECL_NIL)
(size ecl_make_fixnum(1024))
(rehash_size cl_core.rehash_size)
(rehash_threshold cl_core.rehash_threshold))
(rehash_size ecl_ct_default_rehash_size)
(rehash_threshold ecl_ct_default_rehash_threshold))
@ {
cl_object hash = cl__make_hash_table(test, size, rehash_size, rehash_threshold);
if (hash->hash.test == ecl_htt_generic) {

View file

@ -24,85 +24,91 @@
static void
VEbad_lambda_too_many_args(cl_object bytecodes, cl_object frame)
{
FEprogram_error("Too many arguments passed to "
"function ~A~&Argument list: ~S",
2, bytecodes, cl_apply(2, @'list', frame));
ecl_ferror(ECL_EX_VM_BADARG_EXCD, bytecodes, frame);
}
static void
VEbad_lambda_unknown_keyword(cl_object bytecodes, cl_object frame)
{
FEprogram_error("Unknown keyword argument passed to function ~S.~&"
"Argument list: ~S", 2, bytecodes,
cl_apply(2, @'list', frame));
ecl_ferror(ECL_EX_VM_BADARG_UNKK, bytecodes, frame);
}
static void
VEbad_lambda_odd_keys(cl_object bytecodes, cl_object frame)
{
FEprogram_error("Function ~A called with odd number "
"of keyword arguments.",
1, bytecodes);
ecl_ferror(ECL_EX_VM_BADARG_ODDK, bytecodes, frame);
}
static void
VEwrong_arg_type_endp(cl_object reg0)
{
FEwrong_type_only_arg(@[endp], reg0, @[list]);
ecl_ferror(ECL_EX_VM_BADARG_ENDP, ECL_NIL, reg0);
}
static void
VEwrong_arg_type_car(cl_object reg0)
{
FEwrong_type_only_arg(@[car], reg0, @[cons]);
ecl_ferror(ECL_EX_VM_BADARG_CAR, ECL_NIL, reg0);
}
static void
VEwrong_arg_type_cdr(cl_object reg0)
{
FEwrong_type_only_arg(@[cdr], reg0, @[cons]);
ecl_ferror(ECL_EX_VM_BADARG_CDR, ECL_NIL, reg0);
}
static void
VEwrong_arg_type_nth_val(cl_fixnum n)
VEwrong_arg_type_nth_val()
{
FEerror("Wrong index passed to NTH-VAL", 1, ecl_make_fixnum(n));
ecl_ferror(ECL_EX_VM_BADARG_NTH_VAL, ECL_NIL, ECL_NIL);
}
static void
VEwrong_args_progv(cl_object vars, cl_object vals)
{
ecl_ferror(ECL_EX_VM_BADARG_PROGV, vars, vals);
}
static void
VEassignment_to_constant(cl_object var)
{
FEassignment_to_constant(var);
ecl_ferror(ECL_EX_V_CSETQ, var, ECL_NIL);
}
static void
VEbinding_a_constant(cl_object var)
{
ecl_ferror(ECL_EX_V_CBIND, var, ECL_NIL);
}
static void
VEunbound_variable(cl_object var)
{
FEunbound_variable(var);
ecl_ferror(ECL_EX_V_UNBND, var, ECL_NIL);
}
static void
VEwrong_num_arguments(cl_object fname)
VEillegal_variable_name(cl_object name)
{
FEwrong_num_arguments(fname);
ecl_ferror(ECL_EX_V_BNAME, name, ECL_NIL);
}
static void
VEwrong_num_arguments(cl_object fun)
{
ecl_ferror(ECL_EX_F_NARGS, fun, ECL_NIL);
}
static void
VEundefined_function(cl_object fun)
{
FEundefined_function(fun);
ecl_ferror(ECL_EX_F_UNDEF, fun, ECL_NIL);
}
static void
VEinvalid_function(cl_object fun)
{
FEinvalid_function(fun);
}
static void
VEclose_around_arg_type()
{
FEerror("Internal error: ecl_close_around should be called on t_bytecodes or t_bclosure.", 0);
ecl_ferror(ECL_EX_F_INVAL, fun, ECL_NIL);
}
/* ------------------------------ LEXICAL ENV. ------------------------------ */
@ -175,16 +181,22 @@ ecl_lex_env_get_record(cl_object env, int s)
/* -- Lexical and local env operators ------------------------------------------ */
static cl_object
make_lex(cl_index n)
make_lex(cl_index size)
{
return si_make_vector(ECL_T, ecl_make_fixnum(n), ECL_NIL,
ecl_make_fixnum(0), ECL_NIL, ECL_NIL);
cl_object x = ecl_alloc_object(t_vector);
x->vector.elttype = ecl_aet_object;
x->vector.displaced = ECL_NIL;
x->vector.dim = size;
x->vector.fillp = 0;
x->vector.flags = ECL_FLAG_ADJUSTABLE | ECL_FLAG_HAS_FILL_POINTER;
x->vector.self.t = (cl_object *)ecl_alloc(size * sizeof(cl_object));
return x;
}
static void
push_lex(cl_object stack, cl_object new)
{
cl_vector_push(new, stack);
ecl_stack_push(stack, new);
}
/* -------------------- AIDS TO THE INTERPRETER -------------------- */
@ -248,7 +260,7 @@ static cl_object
close_around_self(cl_object fun) {
cl_object v, template;
if(ecl_t_of(fun) != t_bytecodes)
VEclose_around_arg_type();
VEinvalid_function(fun);
template = fun->bytecodes.flex;
if(Null(template)) return fun;
/* Make a closure */
@ -286,7 +298,7 @@ close_around_self_fixup(cl_object fun, cl_object lcl_env, cl_object lex_env) {
fun->bclosure.lex = new_lex;
break;
default:
VEclose_around_arg_type();
VEinvalid_function(fun);
}
}
@ -296,7 +308,7 @@ ecl_close_around(cl_object fun, cl_object lcl_env, cl_object lex_env) {
cl_object v, new_lex, template, entry;
cl_fixnum nlex, idx, ndx;
if(ecl_t_of(fun) != t_bytecodes)
VEclose_around_arg_type();
VEinvalid_function(fun);
template = fun->bytecodes.flex;
if(Null(template)) return fun;
/* Close around */
@ -322,6 +334,32 @@ ecl_close_around(cl_object fun, cl_object lcl_env, cl_object lex_env) {
return v;
}
cl_index
ecl_progv(cl_env_ptr env, cl_object vars0, cl_object values0)
{
cl_object vars = vars0, values = values0;
cl_index n = env->bds_stack.top - env->bds_stack.org;
for (; LISTP(vars) && LISTP(values); vars = ECL_CONS_CDR(vars)) {
if (Null(vars)) {
return n;
} else {
cl_object var = ECL_CONS_CAR(vars);
if (!ECL_SYMBOLP(var) || Null(var))
VEillegal_variable_name(var);
if (var->symbol.stype & ecl_stp_constant)
VEbinding_a_constant(var);
if (Null(values)) {
ecl_bds_bind(env, var, OBJNULL);
} else {
ecl_bds_bind(env, var, ECL_CONS_CAR(values));
values = ECL_CONS_CDR(values);
}
}
}
VEwrong_args_progv(vars0, values0);
_ecl_unexpected_return();
}
static inline cl_object
call_stepper(cl_env_ptr the_env, cl_object form, cl_object delta)
{
@ -371,8 +409,8 @@ ecl_interpret(cl_object frame, cl_object closure, cl_object bytecodes)
/* INV: bytecodes is of type t_bytecodes */
lcl_env = ecl_cast_ptr(cl_object, &frame_lcl);
ecl_cs_check(the_env, ihs);
ecl_ihs_push(the_env, &ihs, bytecodes, closure);
ecl_stack_frame_open(the_env, lcl_env, nlcl);
ecl_ihs_push(the_env, &ihs, bytecodes, closure, lcl_env);
if(nlcl) ecl_stack_frame_open(the_env, lcl_env, nlcl);
frame_aux.t = t_frame;
frame_aux.opened = 0;
frame_aux.base = 0;
@ -385,13 +423,21 @@ ecl_interpret(cl_object frame, cl_object closure, cl_object bytecodes)
the_env->nvalues = 0;
THREAD_NEXT;
}
/* OP_QUOTE
/* OP_QUOTE n{dat}
Sets REG0 to an immediate value.
*/
CASE(OP_QUOTE); {
GET_DATA(reg0, vector, data);
THREAD_NEXT;
}
/* OP_CALLW n{dat}
Calls the immediate value and sets REG0 to the result.
*/
CASE(OP_CALLW); {
GET_DATA(reg0, vector, data);
ecl_apply_from_stack_frame(frame, reg0);
THREAD_NEXT;
}
/* OP_VAR n{lcl}
OP_VARC n{lex}
OP_VARS n{dat}
@ -685,12 +731,12 @@ ecl_interpret(cl_object frame, cl_object closure, cl_object bytecodes)
ptr = ECL_STACK_FRAME_PTR(frame) + frame_index;
end = ptr + limit;
for (; ptr != end; ptr++) {
if (*(ptr++) == @':allow-other-keys') {
if (*(ptr++) == ECL_ALLOW_OTHER_KEYS) {
aok = *ptr;
count -= 2;
/* only the first :allow-other-keys argument is considered */
for (ptr++; ptr != end; ptr++) {
if (*(ptr++) != @':allow-other-keys')
if (*(ptr++) != ECL_ALLOW_OTHER_KEYS)
break;
count -= 2;
}
@ -709,7 +755,7 @@ ecl_interpret(cl_object frame, cl_object closure, cl_object bytecodes)
*/
CASE(OP_EXIT); {
ecl_ihs_pop(the_env);
ecl_stack_frame_close(lcl_env);
if(nlcl) ecl_stack_frame_close(lcl_env);
return reg0;
}
/* OP_FLET nfun{arg}, fun1{object}
@ -1241,7 +1287,7 @@ ecl_interpret(cl_object frame, cl_object closure, cl_object bytecodes)
CASE(OP_NTHVAL); {
cl_fixnum n = ecl_fixnum(ECL_STACK_POP_UNSAFE(the_env));
if (ecl_unlikely(n < 0)) {
VEwrong_arg_type_nth_val(n);
VEwrong_arg_type_nth_val();
} else if ((cl_index)n >= the_env->nvalues) {
reg0 = ECL_NIL;
} else if (n) {

View file

@ -12,29 +12,10 @@
*
*/
/******************************** IMPORTS *****************************/
/* -- Imports ------------------------------------------------------- */
#include <ecl/ecl.h>
#include <limits.h>
#if defined(ECL_MS_WINDOWS_HOST)
# include <windows.h>
# include <shellapi.h>
# define MAXPATHLEN 512
#endif
#ifndef MAXPATHLEN
# ifdef PATH_MAX
# define MAXPATHLEN PATH_MAX
# else
# define NO_PATH_MAX
# include <unistd.h>
# endif
#endif
#ifdef ECL_USE_MPROTECT
# include <sys/mman.h>
# ifndef MAP_FAILED
# define MAP_FAILED -1
# endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -42,254 +23,14 @@
#include <ecl/internal.h>
#include <ecl/ecl-inl.h>
#include "ecl_features.h"
#include "iso_latin_names.h"
/******************************* EXPORTS ******************************/
/* -- Global Initialization ----------------------------------------- */
const char *ecl_self;
static struct cl_env_struct first_env;
/************************ GLOBAL INITIALIZATION ***********************/
/* HEAP */
#if ECL_FIXNUM_BITS <= 32
/* 1GB */
#define HEAP_SIZE_DEFAULT 1073741824L
#else
/* 4GB */
#define HEAP_SIZE_DEFAULT 4294967296L
#endif
static int ARGC;
static char **ARGV;
/* INV: see ecl_option enum in external.h */
cl_fixnum ecl_option_values[ECL_OPT_LIMIT+1] = {
#ifdef GBC_BOEHM_GENGC
1, /* ECL_OPT_INCREMENTAL_GC */
#else
0, /* ECL_OPT_INCREMENTAL_GC */
#endif
1, /* ECL_OPT_TRAP_SIGSEGV */
1, /* ECL_OPT_TRAP_SIGFPE */
1, /* ECL_OPT_TRAP_SIGINT */
1, /* ECL_OPT_TRAP_SIGILL */
1, /* ECL_OPT_TRAP_SIGBUS */
1, /* ECL_OPT_TRAP_SIGPIPE */
1, /* ECL_OPT_TRAP_INTERRUPT_SIGNAL */
#if defined(ECL_THREADS) && defined(HAVE_SIGPROCMASK)
1, /* ECL_OPT_SIGNAL_HANDLING_THREAD */
#else
0, /* ECL_OPT_SIGNAL_HANDLING_THREAD */
#endif
16, /* ECL_OPT_SIGNAL_QUEUE_SIZE */
0, /* ECL_OPT_BOOTED */
8192, /* ECL_OPT_BIND_STACK_SIZE */
1024, /* ECL_OPT_BIND_STACK_SAFETY_AREA */
2048, /* ECL_OPT_FRAME_STACK_SIZE */
128, /* ECL_OPT_FRAME_STACK_SAFETY_AREA */
32768, /* ECL_OPT_LISP_STACK_SIZE */
128, /* ECL_OPT_LISP_STACK_SAFETY_AREA */
ECL_DEFAULT_C_STACK_SIZE, /* ECL_OPT_C_STACK_SIZE */
4*sizeof(cl_index)*1024, /* ECL_OPT_C_STACK_SAFETY_AREA */
HEAP_SIZE_DEFAULT, /* ECL_OPT_HEAP_SIZE */
1024*1024, /* ECL_OPT_HEAP_SAFETY_AREA */
0, /* ECL_OPT_THREAD_INTERRUPT_SIGNAL */
1, /* ECL_OPT_SET_GMP_MEMORY_FUNCTIONS */
1, /* ECL_OPT_USE_SETMODE_ON_FILES */
0};
#if !defined(GBC_BOEHM)
static char stdin_buf[BUFSIZ];
static char stdout_buf[BUFSIZ];
#endif
cl_fixnum
ecl_get_option(int option)
{
if (option >= ECL_OPT_LIMIT || option < 0) {
FEerror("Invalid boot option ~D", 1, ecl_make_fixnum(option));
}
return ecl_option_values[option];
}
void
ecl_set_option(int option, cl_fixnum value)
{
if (option > ECL_OPT_LIMIT || option < 0) {
FEerror("Invalid boot option ~D", 1, ecl_make_fixnum(option));
} else {
if (option < ECL_OPT_BOOTED &&
ecl_option_values[ECL_OPT_BOOTED]) {
FEerror("Cannot change option ~D while ECL is running",
1, ecl_make_fixnum(option));
}
ecl_option_values[option] = value;
}
}
static void
init_env_mp(cl_env_ptr env)
{
#if defined(ECL_THREADS)
env->cleanup = 0;
#else
env->own_process = ECL_NIL;
#endif
}
static void
init_env_int(cl_env_ptr env)
{
env->interrupt_struct = ecl_alloc(sizeof(*env->interrupt_struct));
env->interrupt_struct->pending_interrupt = ECL_NIL;
#ifdef ECL_THREADS
ecl_mutex_init(&env->interrupt_struct->signal_queue_lock, FALSE);
#endif
{
int size = ecl_option_values[ECL_OPT_SIGNAL_QUEUE_SIZE];
env->interrupt_struct->signal_queue = cl_make_list(1, ecl_make_fixnum(size));
}
env->fault_address = env;
env->trap_fpe_bits = 0;
}
static void
init_env_ffi(cl_env_ptr env)
{
#ifdef HAVE_LIBFFI
env->ffi_args_limit = 0;
env->ffi_types = 0;
env->ffi_values = 0;
env->ffi_values_ptrs = 0;
#endif
}
static void
init_env_aux(cl_env_ptr env)
{
/* Reader */
env->string_pool = ECL_NIL;
env->packages_to_be_created = ECL_NIL;
env->packages_to_be_created_p = ECL_NIL;
/* Format (written in C) */
#if !defined(ECL_CMU_FORMAT)
env->fmt_aux_stream = ecl_make_string_output_stream(64, 1);
#endif
/* Bignum arithmetic */
ecl_init_bignum_registers(env);
/* Bytecodes compiler environment */
env->c_env = NULL;
/* CLOS caches */
env->method_cache = ecl_make_cache(64, 4096);
env->slot_cache = ecl_make_cache(3, 4096);
}
void
ecl_init_first_env(cl_env_ptr env)
{
env->default_sigmask = cl_core.default_sigmask;
#ifdef ECL_THREADS
init_threads();
#else
ecl_cs_init(env);
#endif
init_env_mp(env);
init_env_int(env);
init_env_aux(env);
init_env_ffi(env);
init_stacks(env);
}
void
ecl_init_env(cl_env_ptr env)
{
init_env_mp(env);
init_env_int(env);
init_env_aux(env);
init_env_ffi(env);
init_stacks(env);
}
void
_ecl_dealloc_env(cl_env_ptr env)
{
/* Environment cleanup. This is required because the environment is allocated
* using mmap or some other method. */
free_stacks(env);
#ifdef ECL_THREADS
ecl_mutex_destroy(&env->interrupt_struct->signal_queue_lock);
#endif
#if defined(ECL_USE_MPROTECT)
if (munmap(env, sizeof(*env)))
ecl_internal_error("Unable to deallocate environment structure.");
#elif defined(ECL_USE_GUARD_PAGE)
if (!VirtualFree(env, 0, MEM_RELEASE))
ecl_internal_error("Unable to deallocate environment structure.");
#else
ecl_free_unsafe(env);
#endif
}
cl_env_ptr
_ecl_alloc_env(cl_env_ptr parent)
{
/*
* Allocates the lisp environment for a thread. Depending on which
* mechanism we use for detecting delayed signals, we may allocate
* the environment using mmap or the garbage collector.
*
* Note that at this point we are not allocating any other memory
* which is stored via a pointer in the environment. If we would do
* that, an unlucky interrupt by the gc before the allocated
* environment is registered in cl_core.processes could lead to
* memory being freed because the gc is not aware of the pointer to
* the allocated memory in the environment.
*/
cl_env_ptr output;
#if defined(ECL_USE_MPROTECT)
output = (cl_env_ptr) mmap(0, sizeof(*output), PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
if (output == MAP_FAILED)
ecl_internal_error("Unable to allocate environment structure.");
#else
# if defined(ECL_USE_GUARD_PAGE)
output = VirtualAlloc(0, sizeof(*output), MEM_COMMIT, PAGE_READWRITE);
if (output == NULL)
ecl_internal_error("Unable to allocate environment structure.");
# else
output = ecl_malloc(sizeof(*output));
if (output == NULL)
ecl_internal_error("Unable to allocate environment structure.");
# endif
#endif
{
size_t bytes = cl_core.default_sigmask_bytes;
if (bytes == 0) {
output->default_sigmask = 0;
} else if (parent) {
output->default_sigmask = ecl_alloc_atomic(bytes);
memcpy(output->default_sigmask, parent->default_sigmask, bytes);
} else {
output->default_sigmask = cl_core.default_sigmask;
}
}
for (cl_index i = 0; i < ECL_BIGNUM_REGISTER_NUMBER; i++) {
output->big_register[i] = ECL_NIL;
}
output->method_cache = output->slot_cache = NULL;
output->interrupt_struct = NULL;
/*
* An uninitialized environment _always_ disables interrupts. They
* are activated later on by the thread entry point or init_unixint().
*/
output->disable_interrupts = 1;
return output;
}
void
cl_shutdown(void)
@ -310,11 +51,9 @@ cl_shutdown(void)
ecl_tcp_close_all();
#endif
}
ecl_set_option(ECL_OPT_BOOTED, -1);
ecl_halt();
}
ecl_def_ct_single_float(default_rehash_size,1.5f,static,const);
ecl_def_ct_single_float(default_rehash_threshold,0.75f,static,const);
ecl_def_ct_base_string(str_common_lisp,"COMMON-LISP",11,static,const);
ecl_def_ct_base_string(str_common_lisp_user,"COMMON-LISP-USER",16,static,const);
ecl_def_ct_base_string(str_cl,"CL",2,static,const);
@ -337,7 +76,6 @@ ecl_def_ct_base_string(str_gray,"GRAY",4,static,const);
#endif
ecl_def_ct_base_string(str_star_dot_star,"*.*",3,static,const);
ecl_def_ct_base_string(str_rel_star_dot_star,"./*.*",5,static,const);
ecl_def_ct_base_string(str_empty,"",0,static,const);
ecl_def_ct_base_string(str_G,"G",1,static,const);
ecl_def_ct_base_string(str_T,"T",1,static,const);
#ifdef ENABLE_DLOPEN
@ -352,22 +90,6 @@ ecl_def_ct_base_string(str_lsp,"lsp",3,static,const);
ecl_def_ct_base_string(str_LSP,"LSP",3,static,const);
ecl_def_ct_base_string(str_lisp,"lisp",4,static,const);
ecl_def_ct_base_string(str_NIL,"NIL",3,static,const);
ecl_def_ct_base_string(str_slash,"/",1,static,const);
ecl_def_ct_single_float(flt_zero,0,static,const);
ecl_def_ct_single_float(flt_zero_neg,-0.0,static,const);
ecl_def_ct_double_float(dbl_zero,0,static,const);
ecl_def_ct_double_float(dbl_zero_neg,-0.0,static,const);
ecl_def_ct_long_float(ldbl_zero,0,static,const);
ecl_def_ct_long_float(ldbl_zero_neg,-0.0l,static,const);
ecl_def_ct_ratio(plus_half,ecl_make_fixnum(1),ecl_make_fixnum(2),static,const);
ecl_def_ct_ratio(minus_half,ecl_make_fixnum(-1),ecl_make_fixnum(2),static,const);
ecl_def_ct_single_float(flt_one,1,static,const);
ecl_def_ct_single_float(flt_one_neg,-1,static,const);
ecl_def_ct_single_float(flt_two,2,static,const);
ecl_def_ct_complex(flt_imag_unit,&flt_zero_data,&flt_one_data,static,const);
ecl_def_ct_complex(flt_imag_unit_neg,&flt_zero_data,&flt_one_neg_data,static,const);
ecl_def_ct_complex(flt_imag_two,&flt_zero_data,&flt_two_data,static,const);
struct cl_core_struct cl_core = {
.packages = ECL_NIL,
@ -384,9 +106,6 @@ struct cl_core_struct cl_core = {
.c_package = ECL_NIL,
.ffi_package = ECL_NIL,
.pathname_translations = ECL_NIL,
.library_pathname = ECL_NIL,
.terminal_io = ECL_NIL,
.null_stream = ECL_NIL,
.standard_input = ECL_NIL,
@ -396,61 +115,13 @@ struct cl_core_struct cl_core = {
.dispatch_reader = ECL_NIL,
.char_names = ECL_NIL,
.null_string = (cl_object)&str_empty_data,
.plus_half = (cl_object)&plus_half_data,
.minus_half = (cl_object)&minus_half_data,
.imag_unit = (cl_object)&flt_imag_unit_data,
.minus_imag_unit = (cl_object)&flt_imag_unit_neg_data,
.imag_two = (cl_object)&flt_imag_two_data,
.singlefloat_zero = (cl_object)&flt_zero_data,
.doublefloat_zero = (cl_object)&dbl_zero_data,
.singlefloat_minus_zero = (cl_object)&flt_zero_neg_data,
.doublefloat_minus_zero = (cl_object)&dbl_zero_neg_data,
.longfloat_zero = (cl_object)&ldbl_zero_data,
.longfloat_minus_zero = (cl_object)&ldbl_zero_neg_data,
.gensym_prefix = (cl_object)&str_G_data,
.gentemp_prefix = (cl_object)&str_T_data,
.gensym_prefix = ECL_NIL,
.gentemp_prefix = ECL_NIL,
.gentemp_counter = ecl_make_fixnum(0),
.Jan1st1970UT = ECL_NIL,
.system_properties = ECL_NIL,
.first_env = &first_env,
#ifdef ECL_THREADS
.processes = ECL_NIL,
#endif
/* LIBRARIES is an adjustable vector of objects. It behaves as
a vector of weak pointers thanks to the magic in
gbc.d/alloc_2.d */
.libraries = ECL_NIL,
.max_heap_size = 0,
.bytes_consed = ECL_NIL,
.gc_counter = ECL_NIL,
.gc_stats = 0,
.path_max = 0,
#ifdef GBC_BOEHM
.safety_region = NULL,
#endif
.default_sigmask = NULL,
.default_sigmask_bytes = 0,
#ifdef ECL_THREADS
.last_var_index = 0,
.reused_indices = ECL_NIL,
#endif
.slash = (cl_object)&str_slash_data,
.compiler_dispatch = ECL_NIL,
.rehash_size = (cl_object)&default_rehash_size_data,
.rehash_threshold = (cl_object)&default_rehash_threshold_data,
.known_signals = ECL_NIL
};
#if !defined(ECL_MS_WINDOWS_HOST)
@ -475,6 +146,42 @@ maybe_fix_console_stream(cl_object stream)
}
#endif
static void
init_early_symbol(cl_object symbol, cl_object package) {
symbol->symbol.undef_entry = ecl_undefined_function_entry;
ECL_FMAKUNBOUND(symbol);
cl_import2(symbol, package);
cl_export2(symbol, package);
}
static void
init_ecl_symbols()
{
init_early_symbol(ECL_SIGNAL_HANDLERS, cl_core.system_package);
init_early_symbol(ECL_RESTART_CLUSTERS, cl_core.system_package);
init_early_symbol(ECL_INTERRUPTS_ENABLED, cl_core.system_package);
init_early_symbol(ECL_T, cl_core.lisp_package);
init_early_symbol(ECL_UNBOUND, cl_core.system_package);
/* SYSTEM:UNBOUND has an associated function si_unbound that returns it. */
ECL_SYM_FUN(ECL_UNBOUND)
= ecl_make_cfun((cl_objectfn_fixed)si_unbound, ECL_UNBOUND, NULL, 0);
/* Initialize the :ALLOW-OTHER-KEYS symbol (it is not part of cl_symbols). */
{
cl_object p = cl_core.keyword_package;
cl_object s = ECL_ALLOW_OTHER_KEYS;
cl_object n = s->symbol.name;
ECL_SET(s, OBJNULL);
ECL_FMAKUNBOUND(s);
s->symbol.hpack = p;
s->symbol.undef_entry = ecl_undefined_function_entry;
ecl_symbol_type_set(s, ecl_symbol_type(s) | ecl_stp_constant);
ECL_SET(s, s);
p->pack.external = _ecl_sethash(n, p->pack.external, s);
}
}
int
cl_boot(int argc, char **argv)
{
@ -482,39 +189,34 @@ cl_boot(int argc, char **argv)
int i;
cl_env_ptr env;
i = ecl_option_values[ECL_OPT_BOOTED];
if (i) {
if (i < 0) {
/* We have called cl_shutdown and want to use ECL again. */
ecl_set_option(ECL_OPT_BOOTED, 1);
}
return 1;
}
/*ecl_set_option(ECL_OPT_SIGNAL_HANDLING_THREAD, 0);*/
#if !defined(GBC_BOEHM)
setbuf(stdin, stdin_buf);
setbuf(stdout, stdout_buf);
#endif
init_process();
i = ecl_boot();
if (i==1) return 1;
ARGC = argc;
ARGV = argv;
ecl_self = argv[0];
init_unixint(0);
init_alloc(0);
init_big();
ecl_add_module(ecl_module_process);
ecl_add_module(ecl_module_stacks);
ecl_add_module(ecl_module_gc);
ecl_add_module(ecl_module_unixint);
#ifdef ECL_THREADS
ecl_add_module(ecl_module_thread);
#endif
ecl_add_module(ecl_module_bignum);
ecl_add_module(ecl_module_ffi);
ecl_add_module(ecl_module_aux);
/*
* Initialize the per-thread data.
* This cannot come later, because we need to be able to bind
* ext::*interrupts-enabled* while creating packages.
* ECL_INTERRUPTS_ENABLED while creating packages.
*/
env = cl_core.first_env;
ecl_init_first_env(env);
env = ecl_core.first_env;
/* We need to enable GC because a lot of stuff is to be created */
ecl_module_gc->module.enable();
/*
* 1) Initialize symbols and packages
@ -536,27 +238,8 @@ cl_boot(int argc, char **argv)
#endif
cl_num_symbols_in_core=1;
ECL_T->symbol.t = (short)t_symbol;
ECL_T->symbol.value = ECL_T;
ECL_T->symbol.name = str_T;
ECL_T->symbol.cname = ECL_NIL;
ECL_FMAKUNBOUND(ECL_T);
ECL_T->symbol.sfdef = ECL_NIL;
ECL_T->symbol.macfun = ECL_NIL;
ECL_T->symbol.plist = ECL_NIL;
ECL_T->symbol.hpack = ECL_NIL;
ECL_T->symbol.stype = ecl_stp_constant;
ECL_T->symbol.undef_entry = ecl_undefined_function_entry;
#ifdef ECL_THREADS
ECL_T->symbol.binding = ECL_MISSING_SPECIAL_BINDING;
#endif
cl_num_symbols_in_core=2;
#ifdef NO_PATH_MAX
cl_core.path_max = sysconf(_PC_PATH_MAX);
#else
cl_core.path_max = MAXPATHLEN;
#endif
cl_core.gensym_prefix = (cl_object)&str_G_data;
cl_core.gentemp_prefix = (cl_object)&str_T_data;
cl_core.lisp_package =
ecl_make_package(str_common_lisp,
@ -614,18 +297,16 @@ cl_boot(int argc, char **argv)
cl_import2(ECL_NIL, cl_core.lisp_package);
cl_export2(ECL_NIL, cl_core.lisp_package);
ECL_T->symbol.hpack = cl_core.lisp_package;
cl_import2(ECL_T, cl_core.lisp_package);
cl_export2(ECL_T, cl_core.lisp_package);
/* At exit, clean up */
atexit(cl_shutdown);
/* These must come _after_ the packages and NIL/T have been created */
/* These must come _after_ the packages have been created */
init_ecl_symbols();
init_all_symbols();
/* We need to enable GC because a lot of stuff is to be created */
init_alloc(1);
/* Set the default exception handler that coerces exceptions to conditions
that are understood by the condition system. */
ECL_SET(ECL_SIGNAL_HANDLERS, ecl_list1(ECL_SYM_FUN(@'si::exception-handler')));
/*
* Set *default-pathname-defaults* to a temporary fake value. We
@ -647,8 +328,8 @@ cl_boot(int argc, char **argv)
*/
cl_core.char_names = aux =
cl__make_hash_table(@'equalp', ecl_make_fixnum(128), /* size */
cl_core.rehash_size,
cl_core.rehash_threshold);
ecl_ct_default_rehash_size,
ecl_ct_default_rehash_threshold);
for (i = 0; char_names[i].elt.self; i++) {
cl_object name = (cl_object)(char_names + i);
cl_object code = ecl_make_fixnum(i);
@ -674,8 +355,8 @@ cl_boot(int argc, char **argv)
*/
cl_core.system_properties =
cl__make_hash_table(@'equal', ecl_make_fixnum(1024), /* size */
cl_core.rehash_size,
cl_core.rehash_threshold);
ecl_ct_default_rehash_size,
ecl_ct_default_rehash_threshold);
ECL_SET(@'*random-state*', ecl_make_random_state(ECL_T));
@ -741,8 +422,8 @@ cl_boot(int argc, char **argv)
*/
ECL_SET(@'si::*class-name-hash-table*',
cl__make_hash_table(@'eq', ecl_make_fixnum(1024), /* size */
cl_core.rehash_size,
cl_core.rehash_threshold));
ecl_ct_default_rehash_size,
ecl_ct_default_rehash_threshold));
/*
* Features.
@ -776,11 +457,56 @@ cl_boot(int argc, char **argv)
/* Jump to top level */
ECL_SET(@'*package*', cl_core.user_package);
init_unixint(1);
ecl_module_unixint->module.enable();
return 1;
}
/************************* ENVIRONMENT ROUTINES ***********************/
/* -- Module definition (auxiliary structures) ---------------------- */
static cl_object
create_aux()
{
cl_env_ptr the_env = ecl_core.first_env;
the_env->method_cache = NULL;
the_env->slot_cache = NULL;
return ECL_NIL;
}
static cl_object
init_env_aux(cl_env_ptr the_env)
{
/* Reader */
the_env->string_pool = ECL_NIL;
the_env->packages_to_be_created = ECL_NIL;
the_env->packages_to_be_created_p = ECL_NIL;
/* Format (written in C) */
#if !defined(ECL_CMU_FORMAT)
the_env->fmt_aux_stream = ecl_make_string_output_stream(64, 1);
#endif
/* Bytecodes compiler environment */
the_env->c_env = NULL;
/* CLOS caches */
the_env->method_cache = ecl_make_cache(64, 4096);
the_env->slot_cache = ecl_make_cache(3, 4096);
return ECL_NIL;
}
ecl_def_ct_base_string(str_aux, "AUX", 3, static, const);
static struct ecl_module module_aux = {
.name = str_aux,
.create = create_aux,
.enable = ecl_module_no_op,
.init_env = init_env_aux,
.init_cpu = ecl_module_no_op_env,
.free_cpu = ecl_module_no_op_cpu,
.free_env = ecl_module_no_op_env,
.disable = ecl_module_no_op,
.destroy = ecl_module_no_op
};
cl_object ecl_module_aux = (cl_object)&module_aux;
/* -- Operating system environment routines ------------------------- */
@(defun ext::quit (&optional (code ecl_make_fixnum(0)) (kill_all_threads ECL_T))
@ {

919
src/c/mem_gc.d Normal file
View file

@ -0,0 +1,919 @@
/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* vim: set filetype=c tabstop=2 shiftwidth=2 expandtab: */
/* mem_gc.d - automatic memory allocator and garbage collector based on bdwgc */
/* -- imports ---------------------------------------------------------------- */
#include <ecl/ecl.h>
#include <ecl/ecl-inl.h>
#include <ecl/internal.h>
#include <ecl/external.h>
#include <stdio.h>
#ifdef ECL_THREADS
# ifdef ECL_WINDOWS_THREADS
# include <windows.h>
# else
# include <pthread.h>
# endif
#endif
#include <ecl/ecl-inl.h>
#include <ecl/internal.h>
#include <ecl/page.h>
#ifdef ECL_WSOCK
# include <winsock.h>
#endif
#ifdef GBC_BOEHM
# include <gc/gc_mark.h>
#endif
static void (*GC_old_start_callback)(void) = NULL;
static void gather_statistics(void);
static void update_bytes_consed(void);
static void ecl_mark_env(struct cl_env_struct *env);
#ifdef GBC_BOEHM_PRECISE
# if GBC_BOEHM
# undef GBC_BOEHM_PRECISE
# else
# include <gc/gc_typed.h>
# define GBC_BOEHM_OWN_MARKER
static int cl_object_kind, cl_object_mark_proc_index;
static void **cl_object_free_list;
# endif
#endif
/* -- object allocation ------------------------------------------------------ */
void
_ecl_set_max_heap_size(size_t new_size)
{
const cl_env_ptr the_env = ecl_process_env();
ecl_disable_interrupts_env(the_env);
GC_set_max_heap_size(ecl_core.max_heap_size = new_size);
if (new_size == 0) {
cl_index size = ecl_option_values[ECL_OPT_HEAP_SAFETY_AREA];
ecl_core.safety_region = GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(size);
} else if (ecl_core.safety_region) {
GC_FREE(ecl_core.safety_region);
ecl_core.safety_region = 0;
}
ecl_enable_interrupts_env(the_env);
}
static int failure;
static void *
out_of_memory_check(size_t requested_bytes)
{
failure = 1;
return 0;
}
static void
no_warnings(char *msg, GC_word arg)
{
}
static void *
out_of_memory(size_t requested_bytes)
{
const cl_env_ptr the_env = ecl_process_env();
int interrupts = the_env->disable_interrupts;
int method = 0;
void *output;
/* Disable interrupts only with the ECL_INTERRUPTS_ENABLED mechanism to allow
* for writes in the thread local environment */
if (interrupts)
ecl_enable_interrupts_env(the_env);
ecl_bds_bind(the_env, ECL_INTERRUPTS_ENABLED, ECL_NIL);
/* Free the input / output buffers */
the_env->string_pool = ECL_NIL;
/* The out of memory condition may happen in more than one thread */
/* But then we have to ensure the error has not been solved */
#ifdef ECL_THREADS
ecl_mutex_lock(&ecl_core.error_lock);
ECL_UNWIND_PROTECT_BEGIN(the_env)
#endif
{
failure = 0;
GC_gcollect();
GC_set_oom_fn(out_of_memory_check);
{
output = GC_MALLOC(requested_bytes);
GC_set_oom_fn(out_of_memory);
if (output != 0 && failure == 0) {
method = 2;
goto OUTPUT;
}
}
if (ecl_core.max_heap_size == 0) {
/* We did not set any limit in the amount of memory,
* yet we failed, or we had some limits but we have
* not reached them. */
if (ecl_core.safety_region) {
/* We can free some memory and try handling the error */
GC_FREE(ecl_core.safety_region);
the_env->string_pool = ECL_NIL;
ecl_core.safety_region = 0;
method = 0;
} else {
/* No possibility of continuing */
method = 2;
}
} else {
ecl_core.max_heap_size += ecl_option_values[ECL_OPT_HEAP_SAFETY_AREA];
GC_set_max_heap_size(ecl_core.max_heap_size);
method = 1;
}
OUTPUT:
(void)0;
}
#ifdef ECL_THREADS
ECL_UNWIND_PROTECT_EXIT {
ecl_mutex_unlock(&ecl_core.error_lock);
} ECL_UNWIND_PROTECT_END;
#endif
ecl_bds_unwind1(the_env);
ecl_check_pending_interrupts(the_env);
switch (method) {
case 0: cl_error(1, @'ext::storage-exhausted');
break;
case 1: cl_cerror(2, @"Extend heap size", @'ext::storage-exhausted');
break;
case 2:
return output;
default:
ecl_internal_error("Memory exhausted, quitting program.");
break;
}
if (!interrupts)
ecl_disable_interrupts_env(the_env);
ecl_core.max_heap_size += (ecl_core.max_heap_size / 2);
GC_set_max_heap_size(ecl_core.max_heap_size);
/* Default allocation. Note that we do not allocate atomic. */
return GC_MALLOC(requested_bytes);
}
static struct bdw_type_information {
size_t size;
#ifdef GBC_BOEHM_PRECISE
GC_word descriptor;
#endif
cl_object (*allocator)(struct bdw_type_information *);
size_t t;
} bdw_type_info[t_end];
static cl_object
allocate_object_error(struct bdw_type_information *bdw_type_info)
{
printf("\ttype = %d\n", bdw_type_info->t);
ecl_internal_error("allocate_object_error: alloc botch.");
}
static cl_object
allocate_object_atomic(struct bdw_type_information *bdw_type_info)
{
return GC_MALLOC_ATOMIC(bdw_type_info->size);
}
static cl_object
allocate_object_full(struct bdw_type_information *bdw_type_info)
{
return GC_MALLOC(bdw_type_info->size);
}
#ifdef GBC_BOEHM_PRECISE
static cl_object
allocate_object_typed(struct bdw_type_information *bdw_type_info)
{
return GC_malloc_explicitly_typed(bdw_type_info->size, bdw_type_info->descriptor);
}
#endif
#ifdef GBC_BOEHM_OWN_MARKER
static struct GC_ms_entry *
cl_object_mark_proc(void *addr, struct GC_ms_entry *msp, struct GC_ms_entry *msl,
GC_word env)
{
cl_type t = ((cl_object)addr)->d.t;
if (ecl_likely(t > t_start && t < t_end)) {
struct bdw_type_information *info = bdw_type_info + t;
GC_word d = info->descriptor;
GC_word *p;
for (p = addr; d; p++, d<<=1) {
if ((GC_signed_word)d < 0) {
GC_word aux = *p;
if ((aux & 2) ||
aux <= (GC_word)GC_least_plausible_heap_addr ||
aux >= (GC_word)GC_greatest_plausible_heap_addr)
continue;
msp = GC_mark_and_push((void*)aux, (void*)msp,
(void*)msl, (void*)p);
}
}
}
return msp;
}
static cl_object
allocate_object_marked(struct bdw_type_information *bdw_type_info)
{
return GC_generic_malloc(bdw_type_info->size, cl_object_kind);
}
#endif
/* -- weak pointers ---------------------------------------------------------- */
cl_object
ecl_alloc_weak_pointer(cl_object o)
{
const cl_env_ptr the_env = ecl_process_env();
struct ecl_weak_pointer *obj;
ecl_disable_interrupts_env(the_env);
obj = GC_MALLOC_ATOMIC(sizeof(struct ecl_weak_pointer));
ecl_enable_interrupts_env(the_env);
obj->t = t_weak_pointer;
obj->value = o;
if (!ECL_IMMEDIATE(o)) {
GC_GENERAL_REGISTER_DISAPPEARING_LINK((void**)&(obj->value), (void*)o);
si_set_finalizer((cl_object)obj, ECL_T);
}
return (cl_object)obj;
}
static cl_object
ecl_weak_pointer_value(cl_object o)
{
return ecl_weak_pointer(o);
}
cl_object
si_make_weak_pointer(cl_object o)
{
cl_object pointer = ecl_alloc_weak_pointer(o);
@(return pointer);
}
cl_object
si_weak_pointer_value(cl_object o)
{
const cl_env_ptr the_env = ecl_process_env();
cl_object value;
if (ecl_unlikely(ecl_t_of(o) != t_weak_pointer))
FEwrong_type_only_arg(@[ext::weak-pointer-value], o,
@[ext::weak-pointer]);
value = (cl_object)GC_call_with_alloc_lock((GC_fn_type)ecl_weak_pointer_value, o);
if (value) {
ecl_return2(the_env, value, ECL_T);
} else {
ecl_return2(the_env, ECL_NIL, ECL_NIL);
}
}
/* -- graph traversal -------------------------------------------------------- */
void init_bdw_type_info (void)
{
int i;
for (i = 0; i < t_end; i++) {
uintmax_t desc = ecl_type_info[i].descriptor;
bdw_type_info[i].t = i;
bdw_type_info[i].size = ecl_type_info[i].size;
bdw_type_info[i].allocator =
(desc==0) ? allocate_object_atomic : allocate_object_full;
#ifdef GC_BOEHM_PRECISE
bdw_type_info[t_list].descriptor = desc;
#endif
}
#ifdef GC_BOEHM_PRECISE
for (i = 0; i < t_end; i++) {
GC_word descriptor = bdw_type_info[i].descriptor;
int bits = bdw_type_info[i].size / sizeof(GC_word);
if (descriptor) {
#ifdef GBC_BOEHM_OWN_MARKER
bdw_type_info[i].allocator = allocate_object_marked;
descriptor = GC_make_descriptor(&descriptor, bits);
descriptor &= ~GC_DS_TAGS;
#else
GC_word mask = (1 << (bits-1)) - 1;
mask ^= (descriptor >> 1);
bdw_type_info[i].allocator =
(mask == 0) ? allocate_object_full : allocate_object_typed;
descriptor = GC_make_descriptor(&descriptor, bits);
#endif
bdw_type_info[i].descriptor = descriptor;
}
}
#endif /* GBC_BOEHM_PRECISE */
/* INV these cases are handled inline in ecl_alloc_object. */
bdw_type_info[t_list].allocator = allocate_object_error;
bdw_type_info[t_character].allocator = allocate_object_error;
bdw_type_info[t_fixnum].allocator = allocate_object_error;
}
extern void (*GC_push_other_roots)();
static void (*old_GC_push_other_roots)();
static void stacks_scanner();
/* -- finalization ----------------------------------------------------------- */
static void
standard_finalizer(cl_object o)
{
switch (o->d.t) {
#ifdef ENABLE_DLOPEN
case t_codeblock:
ecl_library_close(o);
break;
#endif
case t_stream:
cl_close(1, o);
break;
case t_weak_pointer:
GC_unregister_disappearing_link((void**)&(o->weak.value));
break;
#if 0
case t_bclosure: {
ecl_free_stack(o->bclosure.lex);
o->bclosure.lex = ECL_NIL;
break;
}
#endif
#ifdef ECL_THREADS
case t_lock: {
const cl_env_ptr the_env = ecl_process_env();
ecl_disable_interrupts_env(the_env);
ecl_mutex_destroy(&o->lock.mutex);
ecl_enable_interrupts_env(the_env);
break;
}
case t_condition_variable: {
const cl_env_ptr the_env = ecl_process_env();
ecl_disable_interrupts_env(the_env);
ecl_cond_var_destroy(&o->condition_variable.cv);
ecl_enable_interrupts_env(the_env);
break;
}
case t_barrier: {
const cl_env_ptr the_env = ecl_process_env();
ecl_disable_interrupts_env(the_env);
ecl_mutex_destroy(&o->barrier.mutex);
ecl_cond_var_destroy(&o->barrier.cv);
ecl_enable_interrupts_env(the_env);
break;
}
case t_semaphore: {
const cl_env_ptr the_env = ecl_process_env();
ecl_disable_interrupts_env(the_env);
ecl_mutex_destroy(&o->semaphore.mutex);
ecl_cond_var_destroy(&o->semaphore.cv);
ecl_enable_interrupts_env(the_env);
break;
}
case t_mailbox: {
const cl_env_ptr the_env = ecl_process_env();
ecl_disable_interrupts_env(the_env);
ecl_mutex_destroy(&o->mailbox.mutex);
ecl_cond_var_destroy(&o->mailbox.reader_cv);
ecl_cond_var_destroy(&o->mailbox.writer_cv);
ecl_enable_interrupts_env(the_env);
break;
}
case t_rwlock: {
const cl_env_ptr the_env = ecl_process_env();
ecl_disable_interrupts_env(the_env);
ecl_rwlock_destroy(&o->rwlock.mutex);
ecl_enable_interrupts_env(the_env);
break;
}
case t_process: {
const cl_env_ptr the_env = ecl_process_env();
ecl_disable_interrupts_env(the_env);
ecl_mutex_destroy(&o->process.start_stop_lock);
ecl_cond_var_destroy(&o->process.exit_barrier);
ecl_enable_interrupts_env(the_env);
break;
}
case t_symbol: {
if (o->symbol.binding != ECL_MISSING_SPECIAL_BINDING) {
ecl_atomic_push(&ecl_core.reused_indices, ecl_make_fixnum(o->symbol.binding));
o->symbol.binding = ECL_MISSING_SPECIAL_BINDING;
}
break;
}
#endif /* ECL_THREADS */
default:;
}
}
static void
wrapped_finalizer(cl_object o, cl_object finalizer);
static void
register_finalizer(cl_object o, void *finalized_object,
GC_finalization_proc fn, void *cd,
GC_finalization_proc *ofn, void **ocd)
{
/* Finalizers for some builtin objects are only run when the object is not
* reachable by any means, including through other finalizers which might
* make the object reachable again. The objects must not contain any cyclic
* references for which finalizers are registered.
*
* We don't use this type of finalizer for user-defined finalizers, because
* those might contain cyclic references which would prevent the objects
* from being garbage collected. It is instead the duty of the user to write
* the finalizers in a consistent way.
*
* case t_symbol: is not finalized with the "unreachable" finalizer because
* it might contain cyclic references; Also running the finalizer too early
* doesn't lead to any problems, we will simply choose a new binding index
* the next time a binding is established. */
switch (o->d.t) {
#ifdef ENABLE_DLOPEN
case t_codeblock:
#endif
case t_stream:
#if defined(ECL_THREADS)
case t_lock:
case t_condition_variable:
case t_barrier:
case t_semaphore:
case t_mailbox:
case t_rwlock:
case t_process:
#endif /* ECL_THREADS */
/* Don't delete the standard finalizer. */
if (fn == NULL) {
fn = (GC_finalization_proc)wrapped_finalizer;
cd = ECL_T;
}
GC_REGISTER_FINALIZER_UNREACHABLE(finalized_object, fn, cd, ofn, ocd);
break;
case t_weak_pointer:
#if defined(ECL_THREADS)
case t_symbol:
#endif
/* Don't delete the standard finalizer. */
if (fn == NULL) {
fn = (GC_finalization_proc)wrapped_finalizer;
cd = ECL_T;
}
/* fallthrough */
default:
GC_REGISTER_FINALIZER_NO_ORDER(finalized_object, fn, cd, ofn, ocd);
break;
}
}
static void
deferred_finalizer(cl_object* x)
{
wrapped_finalizer(x[0], x[1]);
}
static void
wrapped_finalizer(cl_object o, cl_object finalizer)
{
if (finalizer != ECL_NIL && finalizer != NULL) {
#ifdef ECL_THREADS
const cl_env_ptr the_env = ecl_process_env_unsafe();
if (!the_env
|| !the_env->own_process
|| the_env->own_process->process.phase < ECL_PROCESS_ACTIVE)
{
/*
* The finalizer is invoked while we are registering or setup a
* new lisp process. As example that may happen when we are
* doing ecl_import_current_thread. That mean the finalizer
* can not be executed right now, so in some way we need to
* queue the finalization. When we return from this function
* the original finalizer is no more registered to o, and if o
* is not anymore reachable it will be colleted. To prevent
* this we need to make this object reachable again after that
* roundtrip and postpone the finalization to the next garbage
* collection. Given that this is a rare condition one way to
* do that is:
*/
GC_finalization_proc ofn;
void *odata;
cl_object* wrapper = GC_MALLOC(2*sizeof(cl_object));
wrapper[0] = o;
wrapper[1] = finalizer;
register_finalizer(o, wrapper,
(GC_finalization_proc)deferred_finalizer, 0,
&ofn, &odata);
return;
}
#endif /* ECL_THREADS */
CL_NEWENV_BEGIN {
if (finalizer != ECL_T) {
funcall(2, finalizer, o);
}
standard_finalizer(o);
} CL_NEWENV_END;
}
}
cl_object
si_get_finalizer(cl_object o)
{
const cl_env_ptr the_env = ecl_process_env();
cl_object output;
GC_finalization_proc ofn;
void *odata;
ecl_disable_interrupts_env(the_env);
register_finalizer(o, o, (GC_finalization_proc)0, 0, &ofn, &odata);
if (ofn == 0) {
output = ECL_NIL;
} else if (ofn == (GC_finalization_proc)wrapped_finalizer) {
output = (cl_object)odata;
} else {
output = ECL_NIL;
}
register_finalizer(o, o, ofn, odata, &ofn, &odata);
ecl_enable_interrupts_env(the_env);
@(return output);
}
void
ecl_set_finalizer_unprotected(cl_object o, cl_object finalizer)
{
GC_finalization_proc ofn;
void *odata;
if (finalizer == ECL_NIL) {
register_finalizer(o, o, (GC_finalization_proc)0, 0, &ofn, &odata);
} else {
GC_finalization_proc newfn;
newfn = (GC_finalization_proc)wrapped_finalizer;
register_finalizer(o, o, newfn, finalizer, &ofn, &odata);
}
}
cl_object
si_set_finalizer(cl_object o, cl_object finalizer)
{
const cl_env_ptr the_env = ecl_process_env();
ecl_disable_interrupts_env(the_env);
ecl_set_finalizer_unprotected(o, finalizer);
ecl_enable_interrupts_env(the_env);
@(return);
}
/* -- GC stats --------------------------------------------------------------- */
/* If we do not build our own version of the library, we do not have
* control over the existence of this variable. */
#if GBC_BOEHM == 0
extern int GC_print_stats;
#else
static int GC_print_stats;
#endif
cl_object
si_gc_stats(cl_object enable)
{
cl_object old_status;
cl_object size1;
cl_object size2;
if (ecl_core.gc_stats == 0) {
old_status = ECL_NIL;
} else if (GC_print_stats) {
old_status = @':full';
} else {
old_status = ECL_T;
}
if (ecl_core.bytes_consed == ECL_NIL) {
ecl_core.bytes_consed = ecl_alloc_object(t_bignum);
mpz_init2(ecl_bignum(ecl_core.bytes_consed), 128);
ecl_core.gc_counter = ecl_alloc_object(t_bignum);
mpz_init2(ecl_bignum(ecl_core.gc_counter), 128);
}
update_bytes_consed();
/* We need fresh copies of the bignums */
size1 = _ecl_big_register_copy(ecl_core.bytes_consed);
size2 = _ecl_big_register_copy(ecl_core.gc_counter);
if (enable == ECL_NIL) {
GC_print_stats = 0;
ecl_core.gc_stats = 0;
} else if (enable == ecl_make_fixnum(0)) {
mpz_set_ui(ecl_bignum(ecl_core.bytes_consed), 0);
mpz_set_ui(ecl_bignum(ecl_core.gc_counter), 0);
} else {
ecl_core.gc_stats = 1;
GC_print_stats = (enable == @':full');
}
@(return size1 size2 old_status);
}
/* This procedure is invoked after garbage collection. Note that we
* cannot cons because this procedure is invoked with the garbage
* collection lock on. */
static void
gather_statistics()
{
/* GC stats rely on bignums */
if (ecl_core.gc_stats) {
update_bytes_consed();
mpz_add_ui(ecl_bignum(ecl_core.gc_counter),
ecl_bignum(ecl_core.gc_counter),
1);
}
if (GC_old_start_callback)
GC_old_start_callback();
}
static void
update_bytes_consed () {
#if GBC_BOEHM == 0
mpz_add_ui(ecl_bignum(ecl_core.bytes_consed),
ecl_bignum(ecl_core.bytes_consed),
GC_get_bytes_since_gc());
#else
/* This is not accurate and may wrap around. We try to detect this
assuming that an overflow in an unsigned integer will produce
a smaller integer.*/
static cl_index bytes = 0;
cl_index new_bytes = GC_get_total_bytes();
if (bytes > new_bytes) {
cl_index wrapped;
wrapped = ~((cl_index)0) - bytes;
mpz_add_ui(ecl_bignum(ecl_core.bytes_consed),
ecl_bignum(ecl_core.bytes_consed),
wrapped);
mpz_add_ui(ecl_bignum(ecl_core.bytes_consed),
ecl_bignum(ecl_core.bytes_consed),
new_bytes);
} else {
mpz_add_ui(ecl_bignum(ecl_core.bytes_consed),
ecl_bignum(ecl_core.bytes_consed),
new_bytes - bytes);
}
bytes = new_bytes;
#endif
}
/* -- garbage collection ----------------------------------------------------- */
static void
ecl_mark_env(struct cl_env_struct *env)
{
/* Environments and stacks are allocated without GC */
if (env->run_stack.org)
GC_push_all((void *)env->run_stack.org, (void *)env->run_stack.top);
if (env->frs_stack.org)
GC_push_all((void *)env->frs_stack.org, (void *)(env->frs_stack.top+1));
if (env->bds_stack.org)
GC_push_all((void *)env->bds_stack.org, (void *)(env->bds_stack.top+1));
#ifdef ECL_THREADS
if (env->bds_stack.tl_bindings)
GC_push_all((void *)env->bds_stack.tl_bindings,
(void *)(env->bds_stack.tl_bindings
+ env->bds_stack.tl_bindings_size));
#endif
GC_push_all((void *)env, (void *)(env + 1));
}
static void
stacks_scanner()
{
cl_object l = ecl_core.libraries;
loop_for_on_unsafe(l) {
cl_object dll = ECL_CONS_CAR(l);
if (dll->cblock.locked) {
GC_push_conditional((void *)dll, (void *)(&dll->cblock + 1), 1);
GC_set_mark_bit((void *)dll);
}
} end_loop_for_on_unsafe(l);
/* ECL runtime */
GC_push_all((void *)(&ecl_core), (void *)(&ecl_core + 1));
GC_push_all((void *)(ECL_SIGNAL_HANDLERS),
(void *)(ECL_SIGNAL_HANDLERS + 1));
/* Common Lisp */
GC_push_all((void *)(&cl_core), (void *)(&cl_core + 1));
GC_push_all((void *)cl_symbols, (void *)(cl_symbols + cl_num_symbols_in_core));
ecl_mark_env(ecl_core.first_env);
#ifdef ECL_THREADS
loop_across_stack_fifo(_env, ecl_core.threads) {
cl_env_ptr env = ecl_cast_ptr(cl_env_ptr, _env);
if(env != ecl_core.first_env)
ecl_mark_env(env);
} end_loop_across_stack();
#endif
if (old_GC_push_other_roots)
(*old_GC_push_other_roots)();
}
void
ecl_register_root(cl_object *p)
{
const cl_env_ptr the_env = ecl_process_env();
ecl_disable_interrupts_env(the_env);
GC_add_roots((char*)p, (char*)(p+1));
ecl_enable_interrupts_env(the_env);
}
cl_object
si_gc(cl_narg narg, ...)
{
const cl_env_ptr the_env = ecl_process_env();
ecl_disable_interrupts_env(the_env);
GC_gcollect();
ecl_enable_interrupts_env(the_env);
@(return);
}
cl_object
si_gc_dump()
{
const cl_env_ptr the_env = ecl_process_env();
ecl_disable_interrupts_env(the_env);
GC_dump();
ecl_enable_interrupts_env(the_env);
@(return);
}
/* -- module definition ------------------------------------------------------ */
static cl_object
alloc_object(cl_type t)
{
struct bdw_type_information *ti = bdw_type_info + t;
return ti->allocator(ti);
}
static void *
alloc_memory(cl_index size)
{
return GC_MALLOC(size);
}
static void *
alloc_manual(cl_index size)
{
return GC_MALLOC_UNCOLLECTABLE(size);
}
static void *
alloc_atomic(cl_index size)
{
return GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(size);
}
void
free_memory(void *ptr)
{
GC_FREE(ptr);
}
static void
free_object(cl_object o)
{
standard_finalizer(o);
free_memory(o);
}
struct ecl_allocator_ops gc_ops = {
.allocate_memory = alloc_memory,
.allocate_atomic = alloc_atomic,
.allocate_manual = alloc_manual,
.allocate_object = alloc_object,
.free_memory = free_memory,
.free_object = free_object
};
static cl_object
create_gc()
{
/*
* Garbage collector restrictions: we set up the garbage collector
* library to work as follows
*
* 1) The garbage collector shall not scan shared libraries
* explicitely.
* 2) We only detect objects that are referenced by a pointer to
* the begining or to the first byte.
* 3) Out of the incremental garbage collector, we only use the
* generational component.
* 4) GC should handle fork() which is used to run subprocess on
* some platforms.
*/
GC_set_no_dls(1);
GC_set_all_interior_pointers(0);
GC_set_time_limit(GC_TIME_UNLIMITED);
#ifndef ECL_MS_WINDOWS_HOST
GC_set_handle_fork(1);
#endif
GC_init();
#ifdef ECL_THREADS
# if GC_VERSION_MAJOR > 7 || GC_VERSION_MINOR > 1
GC_allow_register_threads();
# endif
#endif
if (ecl_option_values[ECL_OPT_INCREMENTAL_GC]) {
GC_enable_incremental();
}
GC_register_displacement(1);
GC_clear_roots();
GC_disable();
#ifdef GBC_BOEHM_PRECISE
# ifdef GBC_BOEHM_OWN_MARKER
cl_object_free_list = (void **)GC_new_free_list_inner();
cl_object_mark_proc_index = GC_new_proc((GC_mark_proc)cl_object_mark_proc);
cl_object_kind = GC_new_kind_inner(cl_object_free_list,
GC_MAKE_PROC(cl_object_mark_proc_index, 0),
FALSE, TRUE);
# endif
#endif /* !GBC_BOEHM_PRECISE */
ecl_core.max_heap_size = ecl_option_values[ECL_OPT_HEAP_SIZE];
GC_set_max_heap_size(ecl_core.max_heap_size);
/* Save some memory for the case we get tight. */
if (ecl_core.max_heap_size == 0) {
cl_index size = ecl_option_values[ECL_OPT_HEAP_SAFETY_AREA];
ecl_core.safety_region = GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(size);
} else if (ecl_core.safety_region) {
ecl_core.safety_region = 0;
}
init_bdw_type_info();
old_GC_push_other_roots = GC_push_other_roots;
GC_push_other_roots = stacks_scanner;
GC_old_start_callback = GC_get_start_callback();
GC_set_start_callback(gather_statistics);
GC_set_java_finalization(1);
GC_set_oom_fn(out_of_memory);
GC_set_warn_proc(no_warnings);
ecl_core.allocator = &gc_ops;
return ECL_NIL;
}
static cl_object
enable_gc ()
{
GC_enable();
return ECL_NIL;
}
static cl_object
disable_gc ()
{
GC_disable();
return ECL_NIL;
}
static cl_object
init_cpu(cl_env_ptr the_env)
{
#ifdef GBC_BOEHM
struct GC_stack_base stack;
GC_get_stack_base(&stack);
the_env->c_stack.org = (char*)stack.mem_base;
# ifdef ECL_THREADS
if (GC_thread_is_registered() == 0) {
GC_register_my_thread(&stack);
}
# endif
#endif
return ECL_NIL;
}
static cl_object
free_cpu()
{
#ifdef GBC_BOEHM
# ifdef ECL_THREADS
if (GC_thread_is_registered() == 1) {
GC_unregister_my_thread();
}
# endif
#endif
return ECL_NIL;
}
ecl_def_ct_base_string(str_gc, "GC", 2, static, const);
static struct ecl_module module_gc = {
.name = str_gc,
.create = create_gc,
.enable = enable_gc,
.init_env = ecl_module_no_op_env,
.init_cpu = init_cpu,
.free_cpu = free_cpu,
.free_env = ecl_module_no_op_env,
.disable = disable_gc,
.destroy = ecl_module_no_op
};
cl_object ecl_module_gc = (cl_object)&module_gc;

View file

@ -2,7 +2,7 @@
/* vim: set filetype=c tabstop=2 shiftwidth=2 expandtab: */
/*
* memory.c - manual memory managament
* memory.c - memory managament
*
* Copyright (c) 2024 Daniel Kochmański
*
@ -32,22 +32,13 @@ out_of_memory()
goto AGAIN;
For now let's crash with an appropriate error. */
ecl_internal_error("*** manual memory allocator: out of memory\n");
ecl_internal_error("*** memory allocator: out of memory\n");
}
void *
ecl_malloc(cl_index n)
{
/* GC-free equivalent of ecl_alloc_atomic. */
const cl_env_ptr the_env = ecl_process_env_unsafe();
void *ptr;
if (!the_env) {
ptr = malloc(n);
} else {
ecl_disable_interrupts_env(the_env);
ptr = malloc(n);
ecl_enable_interrupts_env(the_env);
}
void *ptr = malloc(n);
if (ptr == NULL) out_of_memory();
return ptr;
}
@ -55,23 +46,15 @@ ecl_malloc(cl_index n)
void
ecl_free(void *ptr)
{
const cl_env_ptr the_env = ecl_process_env_unsafe();
if (!the_env) {
free(ptr);
} else {
ecl_disable_interrupts_env(the_env);
free(ptr);
ecl_enable_interrupts_env(the_env);
}
free(ptr);
}
void *
ecl_realloc(void *ptr, cl_index osize, cl_index nsize)
{
void *p = ecl_malloc(nsize);
ecl_copy(p, ptr, (osize < nsize) ? osize : nsize);
ecl_free(ptr);
return p;
ptr = realloc(ptr, nsize);
if (ptr == NULL) out_of_memory();
return ptr;
}
void
@ -79,3 +62,398 @@ ecl_copy(void *dst, void *src, cl_index ndx)
{
memcpy(dst, src, ndx);
}
void
ecl_mset(void *ptr, byte c, cl_index n)
{
memset(ptr, c, n);
}
/* -- Object database ------------------------------------------------------- */
struct ecl_type_information ecl_type_info[t_end];
static void
assert_type_tag(cl_type t)
{
if (ecl_unlikely(t <= t_start || t >= t_end)) {
printf("\ttype = %d\n", t);
ecl_internal_error("Collector called with invalid tag number.");
}
}
cl_index
ecl_object_byte_size(cl_type t)
{
assert_type_tag(t);
return ecl_type_info[t].size;
}
static void
init_type_info(cl_type type, const char *name, cl_index size, uintmax_t desc)
{
ecl_type_info[type].name = name;
ecl_type_info[type].size = size;
ecl_type_info[type].descriptor = desc;
}
/* Note that a bitmap in some cases describe pointers that are not ~cl_object~,
like ~vector.self.t~ and ~readtable.table~. */
static cl_index
to_bitmap(void *x, void *y)
{
cl_index n = (char*)y - (char*)x;
if (n % sizeof(void*))
ecl_internal_error("Misaligned pointer in ECL structure.");
n /= sizeof(void*);
return 1 << n;
}
#define init_tm(type, name, struct_name, descriptor) \
init_type_info(type, name, sizeof(struct struct_name), descriptor)
static void
init_type_info_database(void)
{
union cl_lispunion o;
struct ecl_cons c;
int i;
for (i = 0; i < t_end; i++) {
ecl_type_info[i].t = i;
ecl_type_info[i].size = 0;
ecl_type_info[i].descriptor = 0;
}
ecl_type_info[t_character].name = "CHARACTER";
ecl_type_info[t_fixnum].name = "FIXNUM";
init_tm(t_list, "CONS", ecl_cons,
to_bitmap(&c, &(c.car)) |
to_bitmap(&c, &(c.cdr)));
init_tm(t_bignum, "BIGNUM", ecl_bignum,
to_bitmap(&o, &(ECL_BIGNUM_LIMBS(&o))));
init_tm(t_ratio, "RATIO", ecl_ratio,
to_bitmap(&o, &(o.ratio.num)) |
to_bitmap(&o, &(o.ratio.den)));
init_tm(t_singlefloat, "SINGLE-FLOAT", ecl_singlefloat, 0);
init_tm(t_doublefloat, "DOUBLE-FLOAT", ecl_doublefloat, 0);
init_tm(t_longfloat, "LONG-FLOAT", ecl_long_float, 0);
init_tm(t_complex, "COMPLEX", ecl_complex,
to_bitmap(&o, &(o.gencomplex.real)) |
to_bitmap(&o, &(o.gencomplex.imag)));
#ifdef ECL_COMPLEX_FLOAT
init_tm(t_csfloat, "COMPLEX-SINGLE-FLOAT", ecl_csfloat, 0);
init_tm(t_cdfloat, "COMPLEX-DOUBLE-FLOAT", ecl_cdfloat, 0);
init_tm(t_clfloat, "COMPLEX-LONG-FLOAT", ecl_clfloat, 0);
#endif
init_tm(t_symbol, "SYMBOL", ecl_symbol,
to_bitmap(&o, &(o.symbol.value)) |
to_bitmap(&o, &(o.symbol.gfdef)) |
to_bitmap(&o, &(o.symbol.macfun)) |
to_bitmap(&o, &(o.symbol.sfdef)) |
to_bitmap(&o, &(o.symbol.plist)) |
to_bitmap(&o, &(o.symbol.name)) |
to_bitmap(&o, &(o.symbol.hpack)));
init_tm(t_package, "PACKAGE", ecl_package,
to_bitmap(&o, &(o.pack.name)) |
to_bitmap(&o, &(o.pack.nicknames)) |
to_bitmap(&o, &(o.pack.local_nicknames)) |
to_bitmap(&o, &(o.pack.nicknamedby)) |
to_bitmap(&o, &(o.pack.shadowings)) |
to_bitmap(&o, &(o.pack.uses)) |
to_bitmap(&o, &(o.pack.usedby)) |
to_bitmap(&o, &(o.pack.internal)) |
to_bitmap(&o, &(o.pack.external)));
init_tm(t_hashtable, "HASH-TABLE", ecl_hashtable,
to_bitmap(&o, &(o.hash.data)) |
to_bitmap(&o, &(o.hash.sync_lock)) |
to_bitmap(&o, &(o.hash.generic_test)) |
to_bitmap(&o, &(o.hash.generic_hash)) |
to_bitmap(&o, &(o.hash.rehash_size)) |
to_bitmap(&o, &(o.hash.threshold)));
init_tm(t_array, "ARRAY", ecl_array,
to_bitmap(&o, &(o.array.dims)) |
to_bitmap(&o, &(o.array.self.t)) |
to_bitmap(&o, &(o.array.displaced)));
init_tm(t_vector, "VECTOR", ecl_vector,
to_bitmap(&o, &(o.vector.self.t)) |
to_bitmap(&o, &(o.vector.displaced)));
#ifdef ECL_UNICODE
init_tm(t_string, "STRING", ecl_string,
to_bitmap(&o, &(o.string.self)) |
to_bitmap(&o, &(o.string.displaced)));
#endif
init_tm(t_base_string, "BASE-STRING", ecl_base_string,
to_bitmap(&o, &(o.base_string.self)) |
to_bitmap(&o, &(o.base_string.displaced)));
init_tm(t_bitvector, "BIT-VECTOR", ecl_vector,
to_bitmap(&o, &(o.vector.self.t)) |
to_bitmap(&o, &(o.vector.displaced)));
init_tm(t_stream, "STREAM", ecl_stream,
to_bitmap(&o, &(o.stream.ops)) |
to_bitmap(&o, &(o.stream.object0)) |
to_bitmap(&o, &(o.stream.object1)) |
to_bitmap(&o, &(o.stream.last_byte)) |
to_bitmap(&o, &(o.stream.byte_stack)) |
to_bitmap(&o, &(o.stream.buffer)) |
to_bitmap(&o, &(o.stream.format)) |
to_bitmap(&o, &(o.stream.format_table)));
init_tm(t_random, "RANDOM-STATE", ecl_random,
to_bitmap(&o, &(o.random.value)));
init_tm(t_readtable, "READTABLE", ecl_readtable,
# ifdef ECL_UNICODE
to_bitmap(&o, &(o.readtable.hash)) |
# endif
to_bitmap(&o, &(o.readtable.table)));
init_tm(t_pathname, "PATHNAME", ecl_pathname,
to_bitmap(&o, &(o.pathname.version)) |
to_bitmap(&o, &(o.pathname.type)) |
to_bitmap(&o, &(o.pathname.name)) |
to_bitmap(&o, &(o.pathname.directory)) |
to_bitmap(&o, &(o.pathname.device)) |
to_bitmap(&o, &(o.pathname.host)));
init_tm(t_bytecodes, "BYTECODES", ecl_bytecodes,
to_bitmap(&o, &(o.bytecodes.name)) |
to_bitmap(&o, &(o.bytecodes.definition)) |
to_bitmap(&o, &(o.bytecodes.code)) |
to_bitmap(&o, &(o.bytecodes.data)) |
to_bitmap(&o, &(o.bytecodes.flex)) |
to_bitmap(&o, &(o.bytecodes.file)) |
to_bitmap(&o, &(o.bytecodes.file_position)));
init_tm(t_bclosure, "BCLOSURE", ecl_bclosure,
to_bitmap(&o, &(o.bclosure.code)) |
to_bitmap(&o, &(o.bclosure.lex)));
init_tm(t_cfun, "CFUN", ecl_cfun,
to_bitmap(&o, &(o.cfun.name)) |
to_bitmap(&o, &(o.cfun.block)) |
to_bitmap(&o, &(o.cfun.file)) |
to_bitmap(&o, &(o.cfun.file_position)));
init_tm(t_cfunfixed, "CFUNFIXED", ecl_cfunfixed,
to_bitmap(&o, &(o.cfunfixed.name)) |
to_bitmap(&o, &(o.cfunfixed.block)) |
to_bitmap(&o, &(o.cfunfixed.file)) |
to_bitmap(&o, &(o.cfunfixed.file_position)));
init_tm(t_cclosure, "CCLOSURE", ecl_cclosure,
to_bitmap(&o, &(o.cclosure.env)) |
to_bitmap(&o, &(o.cclosure.block)) |
to_bitmap(&o, &(o.cclosure.file)) |
to_bitmap(&o, &(o.cclosure.file_position)));
init_tm(t_instance, "INSTANCE", ecl_instance,
to_bitmap(&o, &(o.instance.clas)) |
to_bitmap(&o, &(o.instance.slotds)) |
to_bitmap(&o, &(o.instance.slots)));
#ifdef ECL_THREADS
init_tm(t_process, "PROCESS", ecl_process,
to_bitmap(&o, &(o.process.name)) |
to_bitmap(&o, &(o.process.function)) |
to_bitmap(&o, &(o.process.args)) |
to_bitmap(&o, &(o.process.inherit_bindings_p)) |
to_bitmap(&o, &(o.process.exit_values)) |
to_bitmap(&o, &(o.process.woken_up)) |
to_bitmap(&o, &(o.process.env)));
init_tm(t_lock, "LOCK", ecl_lock,
to_bitmap(&o, &(o.lock.name)) |
to_bitmap(&o, &(o.lock.owner)));
init_tm(t_rwlock, "RWLOCK", ecl_rwlock,
to_bitmap(&o, &(o.rwlock.name)));
init_tm(t_condition_variable, "CONDITION-VARIABLE", ecl_condition_variable, 0);
init_tm(t_semaphore, "SEMAPHORE", ecl_semaphore,
to_bitmap(&o, &(o.semaphore.name)));
init_tm(t_barrier, "BARRIER", ecl_barrier,
to_bitmap(&o, &(o.barrier.name)));
init_tm(t_mailbox, "MAILBOX", ecl_mailbox,
to_bitmap(&o, &(o.mailbox.name)) |
to_bitmap(&o, &(o.mailbox.data)));
#endif
init_tm(t_codeblock, "CODEBLOCK", ecl_codeblock,
to_bitmap(&o, &(o.cblock.data)) |
to_bitmap(&o, &(o.cblock.temp_data)) |
to_bitmap(&o, &(o.cblock.next)) |
to_bitmap(&o, &(o.cblock.name)) |
to_bitmap(&o, &(o.cblock.links)) |
to_bitmap(&o, &(o.cblock.source)) |
to_bitmap(&o, &(o.cblock.refs)) |
to_bitmap(&o, &(o.cblock.error)));
init_tm(t_foreign, "FOREIGN", ecl_foreign,
to_bitmap(&o, &(o.foreign.data)) |
to_bitmap(&o, &(o.foreign.tag)));
init_tm(t_frame, "STACK-FRAME", ecl_stack_frame,
to_bitmap(&o, &(o.frame.env)));
init_tm(t_exception, "EXCEPTION", ecl_exception,
to_bitmap(&o, &(o.exception.arg1)) |
to_bitmap(&o, &(o.exception.arg2)) |
to_bitmap(&o, &(o.exception.arg3)));
init_tm(t_module, "MODULE", ecl_module, 0);
init_tm(t_weak_pointer, "WEAK-POINTER", ecl_weak_pointer, 0);
#ifdef ECL_SSE2
init_tm(t_sse_pack, "SSE-PACK", ecl_sse_pack, 0);
#endif
}
/* -- Constructors ---------------------------------------------------------- */
cl_object
ecl_alloc_object(cl_type t)
{
assert_type_tag(t);
switch(t) {
case t_list: /* Small cons (no d.t) */
return ecl_cons(ECL_NIL, ECL_NIL);
case t_character:
return ECL_CODE_CHAR(' '); /* Immediate character */
case t_fixnum:
return ecl_make_fixnum(0); /* Immediate fixnum */
default:
{
const cl_env_ptr the_env = ecl_process_env_unsafe();
cl_object o;
if(the_env) ecl_disable_interrupts_env(the_env);
o = ecl_core.allocator->allocate_object(t);
o->d.t = t;
if(the_env) ecl_enable_interrupts_env(the_env);
return o;
}
}
}
void *
ecl_alloc(cl_index n)
{
const cl_env_ptr the_env = ecl_process_env_unsafe();
void *ptr = NULL;
if(!the_env) {
return ecl_core.allocator->allocate_memory(n);
} else {
ecl_disable_interrupts_env(the_env);
ptr = ecl_core.allocator->allocate_memory(n);
ecl_enable_interrupts_env(the_env);
}
return ptr;
}
void *
ecl_alloc_atomic(cl_index n)
{
const cl_env_ptr the_env = ecl_process_env_unsafe();
void *ptr = NULL;
if(!the_env) {
return ecl_core.allocator->allocate_atomic(n);
} else {
ecl_disable_interrupts_env(the_env);
ptr = ecl_core.allocator->allocate_atomic(n);
ecl_enable_interrupts_env(the_env);
}
return ptr;
}
void *
ecl_alloc_manual(cl_index n)
{
const cl_env_ptr the_env = ecl_process_env_unsafe();
void *ptr = NULL;
if(!the_env) {
return ecl_core.allocator->allocate_manual(n);
} else {
ecl_disable_interrupts_env(the_env);
ptr = ecl_core.allocator->allocate_manual(n);
ecl_enable_interrupts_env(the_env);
}
return ptr;
}
void
ecl_free_object(cl_object ptr)
{
const cl_env_ptr the_env = ecl_process_env_unsafe();
if(!the_env) {
ecl_core.allocator->free_object(ptr);
} else {
ecl_disable_interrupts_env(the_env);
ecl_core.allocator->free_object(ptr);
ecl_enable_interrupts_env(the_env);
}
}
void
ecl_dealloc(void *ptr)
{
const cl_env_ptr the_env = ecl_process_env_unsafe();
if(!the_env) {
ecl_core.allocator->free_memory(ptr);
} else {
ecl_disable_interrupts_env(the_env);
ecl_core.allocator->free_memory(ptr);
ecl_enable_interrupts_env(the_env);
}
}
/* -- Helpers --------------------------------------------------------------- */
cl_object /* used by bignum.d */
ecl_alloc_compact_object(cl_type t, cl_index extra_space)
{
cl_index size = ecl_type_info[t].size;
cl_object x = ecl_alloc_atomic(size + extra_space);
x->array.t = t;
x->array.displaced = (void*)(((char*)x) + size);
return x;
}
cl_object
ecl_cons(cl_object a, cl_object d)
{
struct ecl_cons *obj = ecl_alloc(sizeof(struct ecl_cons));
#ifdef ECL_SMALL_CONS
obj->car = a;
obj->cdr = d;
return ECL_PTR_CONS(obj);
#else
obj->t = t_list;
obj->car = a;
obj->cdr = d;
return (cl_object)obj;
#endif
}
cl_object
ecl_append_unsafe(cl_object x, cl_object y)
{
cl_object head = ECL_NIL, cons;
cl_object *tail = &head;
loop_for_on_unsafe(x) {
cons = ecl_list1(ECL_CONS_CAR(x));
*tail = cons;
tail = &ECL_CONS_CDR(cons);
} end_loop_for_on_unsafe(x);
*tail = y;
return head;
}
/* -- Rudimentary manual memory allocator ----------------------------------- */
static cl_object
alloc_object(cl_type t)
{
struct ecl_type_information *ti = ecl_type_info + t;
return ecl_malloc(ti->size);
}
static void
free_object(cl_object o)
{
/* FIXME this should invoke the finalizer! That is - reify finalizers here. */
ecl_free(o);
}
struct ecl_allocator_ops manual_allocator = {
.allocate_memory = ecl_malloc,
.allocate_atomic = ecl_malloc,
.allocate_manual = ecl_malloc,
.allocate_object = alloc_object,
.free_memory = ecl_free,
.free_object = free_object
};
void
init_memory ()
{
init_type_info_database();
ecl_core.allocator = &manual_allocator;
}

188
src/c/module.d Normal file
View file

@ -0,0 +1,188 @@
/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* vim: set filetype=c tabstop=2 shiftwidth=2 expandtab: */
/* module.c - managing runtime modules */
/* -- imports ---------------------------------------------------------------- */
#include <ecl/ecl.h>
#include <ecl/ecl-inl.h>
#include <ecl/internal.h>
#include <ecl/external.h>
/* -- test module ------------------------------------------------------------ */
static cl_object create() {
printf("DUMMY: Creating the module!\n");
return ECL_NIL;
}
static cl_object enable() {
printf("DUMMY: Enabling the module!\n");
return ECL_NIL;
}
static cl_object init_env(cl_env_ptr the_env) {
#ifdef ECL_THREADS
ecl_thread_t thread_id = the_env->thread;
printf("DUMMY: init_env [cpu %p env %p]\n", &thread_id, the_env);
#else
printf("DUMMY: init_env [env %p]\n", the_env);
#endif
return ECL_NIL;
}
static cl_object init_cpu(cl_env_ptr the_env) {
#ifdef ECL_THREADS
ecl_thread_t thread_id = the_env->thread;
printf("DUMMY: init_cpu [cpu %p env %p]\n", &thread_id, the_env);
#else
printf("DUMMY: init_cpu [env %p]\n", the_env);
#endif
return ECL_NIL;
}
static cl_object free_cpu(cl_env_ptr the_env) {
#ifdef ECL_THREADS
ecl_thread_t thread_id = the_env->thread;
printf("DUMMY: free_cpu [cpu %p env %p]\n", &thread_id, the_env);
#else
printf("DUMMY: free_cpu [env %p]\n", the_env);
#endif
return ECL_NIL;
}
static cl_object free_env(cl_env_ptr the_env) {
#ifdef ECL_THREADS
ecl_thread_t thread_id = the_env->thread;
printf("DUMMY: free_env [cpu %p env %p]\n", &thread_id, the_env);
#else
printf("DUMMY: free_env [env %p]\n", the_env);
#endif
return ECL_NIL;
}
static cl_object disable() {
printf("DUMMY: Disabling the module!\n");
return ECL_NIL;
}
static cl_object destroy() {
printf("DUMMY: Destroying the module!\n");
return ECL_NIL;
}
ecl_def_ct_base_string(str_dummy, "DUMMY", 5, static, const);
static struct ecl_module module_dummy = {
.name = str_dummy,
.create = create,
.enable = enable,
.init_env = init_env,
.init_cpu = init_cpu,
.free_cpu = free_cpu,
.free_env = free_env,
.disable = disable,
.destroy = destroy
};
cl_object ecl_module_dummy = (cl_object)&module_dummy;
/* -- implementation --------------------------------------------------------- */
cl_object
ecl_module_no_op(void)
{
return ECL_NIL;
}
cl_object
ecl_module_no_op_env(cl_env_ptr the_env)
{
return ECL_NIL;
}
cl_object
ecl_module_no_op_cpu(cl_env_ptr the_env)
{
return ECL_NIL;
}
cl_object
ecl_add_module(cl_object self)
{
self->module.create();
self->module.init_cpu(ecl_core.first_env);
self->module.init_env(ecl_core.first_env);
ecl_stack_push(ecl_core.modules, self);
return ECL_NIL;
}
cl_object
ecl_del_module(cl_object self)
{
ecl_stack_del(ecl_core.modules, self);
self->module.disable();
self->module.free_env(ecl_core.first_env);
self->module.free_cpu(ecl_core.first_env);
self->module.destroy();
return ECL_NIL;
}
cl_object
ecl_modules_init_env(cl_env_ptr the_env) {
loop_across_stack_fifo(var, ecl_core.modules) {
/* printf("> init_env: %s\n", (var->module.name)->base_string.self); */
var->module.init_env(the_env);
/* printf("< init_env: %s\n", (var->module.name)->base_string.self); */
} end_loop_across_stack();
return ECL_NIL;
}
cl_object
ecl_modules_init_cpu(cl_env_ptr the_env) {
loop_across_stack_fifo(var, ecl_core.modules) {
/* printf("> init_cpu: %s\n", (var->module.name)->base_string.self); */
var->module.init_cpu(the_env);
/* printf("< init_cpu: %s\n", (var->module.name)->base_string.self); */
} end_loop_across_stack();
return ECL_NIL;
}
cl_object
ecl_modules_free_cpu(cl_env_ptr the_env) {
loop_across_stack_filo(var, ecl_core.modules) {
/* printf("> free_cpu: %s\n", (var->module.name)->base_string.self); */
var->module.free_cpu(the_env);
/* printf("< free_cpu: %s\n", (var->module.name)->base_string.self); */
} end_loop_across_stack();
return ECL_NIL;
}
cl_object
ecl_modules_free_env(cl_env_ptr the_env) {
loop_across_stack_filo(var, ecl_core.modules) {
/* printf("> free_env: %s\n", (var->module.name)->base_string.self); */
var->module.free_env(the_env);
/* printf("< free_env: %s\n", (var->module.name)->base_string.self); */
} end_loop_across_stack();
return ECL_NIL;
}
/* INV all modules must be loaded before we make new threads. */
/* FIXME enforce this invariant. */
void
init_modules(void)
{
cl_object self = ecl_make_stack(16);
ecl_core.modules = self;
}
void
free_modules(void)
{
loop_across_stack_filo(var, ecl_core.modules) {
ecl_del_module(var);
} end_loop_across_stack();
ecl_free_stack(ecl_core.modules);
ecl_core.modules = ECL_NIL;
}

1226
src/c/nucl.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -431,21 +431,21 @@ cl_imagpart(cl_object x)
break;
case t_singlefloat:
if (signbit(ecl_single_float(x)))
x = cl_core.singlefloat_minus_zero;
x = ecl_ct_singlefloat_minus_zero;
else
x = cl_core.singlefloat_zero;
x = ecl_ct_singlefloat_zero;
break;
case t_doublefloat:
if (signbit(ecl_double_float(x)))
x = cl_core.doublefloat_minus_zero;
x = ecl_ct_doublefloat_minus_zero;
else
x = cl_core.doublefloat_zero;
x = ecl_ct_doublefloat_zero;
break;
case t_longfloat:
if (signbit(ecl_long_float(x)))
x = cl_core.longfloat_minus_zero;
x = ecl_ct_longfloat_minus_zero;
else
x = cl_core.longfloat_zero;
x = ecl_ct_longfloat_zero;
break;
case t_complex:
x = x->gencomplex.imag;

View file

@ -501,9 +501,9 @@ ecl_make_single_float(float f)
if (f == (float)0.0) {
#if defined(ECL_SIGNED_ZERO)
if (signbit(f))
return cl_core.singlefloat_minus_zero;
return ecl_ct_singlefloat_minus_zero;
#endif
return cl_core.singlefloat_zero;
return ecl_ct_singlefloat_zero;
}
x = ecl_alloc_object(t_singlefloat);
ecl_single_float(x) = f;
@ -519,9 +519,9 @@ ecl_make_double_float(double f)
if (f == (double)0.0) {
#if defined(ECL_SIGNED_ZERO)
if (signbit(f))
return cl_core.doublefloat_minus_zero;
return ecl_ct_doublefloat_minus_zero;
#endif
return cl_core.doublefloat_zero;
return ecl_ct_doublefloat_zero;
}
x = ecl_alloc_object(t_doublefloat);
ecl_double_float(x) = f;
@ -537,9 +537,9 @@ ecl_make_long_float(long double f)
if (f == (long double)0.0) {
#if defined(ECL_SIGNED_ZERO)
if (signbit(f))
return cl_core.longfloat_minus_zero;
return ecl_ct_longfloat_minus_zero;
#endif
return cl_core.longfloat_zero;
return ecl_ct_longfloat_zero;
}
x = ecl_alloc_object(t_longfloat);
x->longfloat.value = f;

View file

@ -15,11 +15,19 @@
#define ECL_INCLUDE_MATH_H
#include <ecl/ecl.h>
#include <ecl/ecl-inl.h>
#include <ecl/internal.h>
#include <ecl/impl/math_fenv.h>
#pragma STDC FENV_ACCESS ON
ecl_def_ct_single_float(ecl_ct_flt_zero,0,static,const);
ecl_def_ct_single_float(ecl_ct_flt_one,1,static,const);
ecl_def_ct_single_float(ecl_ct_flt_one_neg,-1,static,const);
ecl_def_ct_complex(ecl_ct_imag_unit,ecl_ct_flt_zero,ecl_ct_flt_one,static,const);
ecl_def_ct_complex(ecl_ct_minus_imag_unit,ecl_ct_flt_zero,ecl_ct_flt_one_neg,static,const);
cl_object
ecl_atan2(cl_object y, cl_object x)
{
@ -53,20 +61,20 @@ ecl_atan1(cl_object y)
{
if (ECL_COMPLEXP(y)) {
#if 0 /* ANSI states it should be this first part */
cl_object z = ecl_times(cl_core.imag_unit, y);
cl_object z = ecl_times(ecl_ct_imag_unit, y);
z = ecl_plus(ecl_log1(ecl_one_plus(z)),
ecl_log1(ecl_minus(ecl_make_fixnum(1), z)));
z = ecl_divide(z, ecl_times(ecl_make_fixnum(2),
cl_core.imag_unit));
ecl_ct_imag_unit));
#else
cl_object z1, z = ecl_times(cl_core.imag_unit, y);
cl_object z1, z = ecl_times(ecl_ct_imag_unit, y);
z = ecl_one_plus(z);
z1 = ecl_times(y, y);
z1 = ecl_one_plus(z1);
z1 = ecl_sqrt(z1);
z = ecl_divide(z, z1);
z = ecl_log1(z);
z = ecl_times(cl_core.minus_imag_unit, z);
z = ecl_times(ecl_ct_minus_imag_unit, z);
#endif /* ANSI */
return z;
} else {

View file

@ -87,12 +87,12 @@ ecl_round2_integer(const cl_env_ptr the_env, cl_object x, cl_object y, cl_object
cl_object q1 = ecl_integer_divide(q->ratio.num, q->ratio.den);
cl_object r = ecl_minus(q, q1);
if (ecl_minusp(r)) {
int c = ecl_number_compare(cl_core.minus_half, r);
int c = ecl_number_compare(ecl_ct_minus_half, r);
if (c > 0 || (c == 0 && ecl_oddp(q1))) {
q1 = ecl_one_minus(q1);
}
} else {
int c = ecl_number_compare(r, cl_core.plus_half);
int c = ecl_number_compare(r, ecl_ct_plus_half);
if (c > 0 || (c == 0 && ecl_oddp(q1))) {
q1 = ecl_one_plus(q1);
}

View file

@ -76,7 +76,7 @@ ecl_sqrt_long_float(cl_object x)
static cl_object
ecl_sqrt_complex(cl_object x)
{
return ecl_expt(x, cl_core.plus_half);
return ecl_expt(x, ecl_ct_plus_half);
}
#ifdef ECL_COMPLEX_FLOAT

View file

@ -23,8 +23,8 @@
* NOTE 1: we only need to use the package locks when reading/writing the hash
* tables, or changing the fields of a package. We do not need the locks to
* read lists from the packages (i.e. list of shadowing symbols, used
* packages, etc), or from the global environment (cl_core.packages_list) if
* we do not destructively modify them (For instance, use ecl_remove_eq
* packages, etc), or from the global environment (cl_core.packages_list)
* if we do not destructively modify them (For instance, use ecl_remove_eq
* instead of ecl_delete_eq).
*/
/*
@ -114,8 +114,8 @@ make_package_hashtable()
{
return cl__make_hash_table(@'package', /* package hash table */
ecl_make_fixnum(128), /* initial size */
cl_core.rehash_size,
cl_core.rehash_threshold);
ecl_ct_default_rehash_size,
ecl_ct_default_rehash_threshold);
}
static cl_object
@ -270,7 +270,7 @@ ecl_make_package(cl_object name, cl_object nicknames,
nicknamed->pack.nicknamedby = CONS(x, nicknamed->pack.nicknamedby);
} end_loop_for_in;
/* Finally, add it to the list of packages */
cl_core.packages = CONS(x, cl_core.packages);
cl_core.packages = ecl_cons(x, cl_core.packages);
OUTPUT:
(void)0;
} ECL_WITH_GLOBAL_ENV_WRLOCK_END;

View file

@ -461,7 +461,7 @@ parse_word(cl_object s, delim_fn delim, int flags, cl_index start,
case 0:
if (flags & WORD_EMPTY_IS_NIL)
return ECL_NIL;
return cl_core.null_string;
return ecl_ct_null_string;
case 1:
if (ecl_char(s,j) == '*')
return @':wild';
@ -505,7 +505,7 @@ parse_directories(cl_object s, int flags, cl_index start, cl_index end,
cl_object part = parse_word(s, delim, flags, j, end, &i);
if (part == @':error' || part == ECL_NIL)
break;
if (part == cl_core.null_string) { /* "/", ";" */
if (part == ecl_ct_null_string) { /* "/", ";" */
if (j != start) {
if (flags & WORD_LOGICAL)
return @':error';
@ -525,7 +525,7 @@ ecl_logical_hostname_p(cl_object host)
{
if (!ecl_stringp(host))
return FALSE;
return !Null(ecl_assqlp(host, cl_core.pathname_translations));
return !Null(ecl_assqlp(host, ecl_core.pathname_translations));
}
/*
@ -562,7 +562,7 @@ ecl_parse_namestring(cl_object s, cl_index start, cl_index end, cl_index *ep,
bool logical;
if (start == end) {
host = device = path = name = type = aux = version = @'nil';
host = device = path = name = type = aux = version = ECL_NIL;
logical = 0;
*ep = end;
goto make_it;
@ -900,8 +900,8 @@ si_coerce_to_filename(cl_object pathname_orig)
pathname_orig->pathname.type,
pathname_orig->pathname.version);
}
if (cl_core.path_max != -1 &&
ecl_length(namestring) >= cl_core.path_max - 16)
if (ecl_core.path_max != -1 &&
ecl_length(namestring) >= ecl_core.path_max - 16)
FEerror("Too long filename: ~S.", 1, namestring);
return namestring;
}
@ -1318,7 +1318,7 @@ cl_host_namestring(cl_object pname)
pname = cl_pathname(pname);
pname = pname->pathname.host;
if (Null(pname) || pname == @':wild')
pname = cl_core.null_string;
pname = ecl_ct_null_string;
@(return pname);
}
@ -1542,7 +1542,7 @@ coerce_to_from_pathname(cl_object x, cl_object host)
FEerror("Wrong host syntax ~S", 1, host);
}
/* Find its translation list */
pair = ecl_assqlp(host, cl_core.pathname_translations);
pair = ecl_assqlp(host, ecl_core.pathname_translations);
if (set == OBJNULL) {
@(return ((pair == ECL_NIL)? ECL_NIL : CADR(pair)));
}
@ -1552,7 +1552,7 @@ coerce_to_from_pathname(cl_object x, cl_object host)
}
if (pair == ECL_NIL) {
pair = CONS(host, CONS(ECL_NIL, ECL_NIL));
cl_core.pathname_translations = CONS(pair, cl_core.pathname_translations);
ecl_core.pathname_translations = CONS(pair, ecl_core.pathname_translations);
}
for (l = set, set = ECL_NIL; !ecl_endp(l); l = CDR(l)) {
cl_object item = CAR(l);

View file

@ -237,81 +237,6 @@ cl_eq(cl_object x, cl_object y)
@(return ((x == y) ? ECL_T : ECL_NIL));
}
/*
* EQL-comparison of floats. If we are using signed zeros and NaNs,
* numeric comparison of floating points is not equivalent to bit-wise
* equality. In particular every two NaNs always give false
* (= #1=(/ 0.0 0.0) #1#) => NIL
* and signed zeros always compare equal
* (= 0 -0.0) => T
* which is not the same as what EQL should return
* (EQL #1=(/ 0.0 0.0) #1#) => T
* (EQL 0 -0.0) => NIL
*
* Furthermore, we can not use bit comparisons because in some platforms
* long double has unused bits that makes two long floats be = but not eql.
*/
#if !defined(ECL_SIGNED_ZERO) && !defined(ECL_IEEE_FP)
#define FLOAT_EQL(name, type) \
static bool name(type a, type b) { return a == b; }
#else
#define FLOAT_EQL(name, type) \
static bool name(type a, type b) { \
if (a == b) return signbit(a) == signbit(b); \
if (isnan(a) || isnan(b)) return isnan(a) && isnan(b); \
return 0; \
}
#endif
FLOAT_EQL(float_eql, float);
FLOAT_EQL(double_eql, double);
FLOAT_EQL(long_double_eql, long double);
#undef FLOAT_EQL
bool
ecl_eql(cl_object x, cl_object y)
{
if (x == y)
return TRUE;
if (ECL_IMMEDIATE(x) || ECL_IMMEDIATE(y))
return FALSE;
if (x->d.t != y->d.t)
return FALSE;
switch (x->d.t) {
case t_bignum:
return (_ecl_big_compare(x, y) == 0);
case t_ratio:
return (ecl_eql(x->ratio.num, y->ratio.num) &&
ecl_eql(x->ratio.den, y->ratio.den));
case t_singlefloat:
return float_eql(ecl_single_float(x), ecl_single_float(y));
case t_longfloat:
return long_double_eql(ecl_long_float(x), ecl_long_float(y));
case t_doublefloat:
return double_eql(ecl_double_float(x), ecl_double_float(y));
case t_complex:
return (ecl_eql(x->gencomplex.real, y->gencomplex.real) &&
ecl_eql(x->gencomplex.imag, y->gencomplex.imag));
#ifdef ECL_COMPLEX_FLOAT
case t_csfloat:
return (float_eql(crealf(ecl_csfloat(x)), crealf(ecl_csfloat(y))) &&
float_eql(cimagf(ecl_csfloat(x)), cimagf(ecl_csfloat(y))));
case t_cdfloat:
return (double_eql(creal(ecl_cdfloat(x)), creal(ecl_cdfloat(y))) &&
double_eql(cimag(ecl_cdfloat(x)), cimag(ecl_cdfloat(y))));
case t_clfloat:
return (long_double_eql(creall(ecl_clfloat(x)), creall(ecl_clfloat(y))) &&
long_double_eql(cimagl(ecl_clfloat(x)), cimagl(ecl_clfloat(y))));
#endif
#ifdef ECL_SSE2
case t_sse_pack:
return !memcmp(x->sse.data.b8, y->sse.data.b8, 16);
#endif
default:
return FALSE;
}
}
cl_object
cl_eql(cl_object x, cl_object y)
{
@ -344,39 +269,17 @@ ecl_equal(cl_object x, cl_object y)
case t_fixnum:
return FALSE;
case t_bignum:
return (tx == ty) && (_ecl_big_compare(x,y) == 0);
case t_ratio:
return (tx == ty) && ecl_eql(x->ratio.num, y->ratio.num) &&
ecl_eql(x->ratio.den, y->ratio.den);
case t_singlefloat: {
if (tx != ty) return 0;
return float_eql(ecl_single_float(x), ecl_single_float(y));
}
case t_doublefloat: {
if (tx != ty) return 0;
return double_eql(ecl_double_float(x), ecl_double_float(y));
}
case t_longfloat: {
if (tx != ty) return 0;
return long_double_eql(ecl_long_float(x), ecl_long_float(y));
}
case t_singlefloat:
case t_doublefloat:
case t_longfloat:
case t_complex:
return (tx == ty) && ecl_eql(x->gencomplex.real, y->gencomplex.real) &&
ecl_eql(x->gencomplex.imag, y->gencomplex.imag);
#ifdef ECL_COMPLEX_FLOAT
case t_csfloat:
if (tx != ty) return 0;
return (float_eql(crealf(ecl_csfloat(x)), crealf(ecl_csfloat(y))) &&
float_eql(cimagf(ecl_csfloat(x)), cimagf(ecl_csfloat(y))));
case t_cdfloat:
if (tx != ty) return 0;
return (double_eql(creal(ecl_cdfloat(x)), creal(ecl_cdfloat(y))) &&
double_eql(cimag(ecl_cdfloat(x)), cimag(ecl_cdfloat(y))));
case t_clfloat:
if (tx != ty) return 0;
return (long_double_eql(creall(ecl_clfloat(x)), creall(ecl_clfloat(y))) &&
long_double_eql(cimagl(ecl_clfloat(x)), cimagl(ecl_clfloat(y))));
#endif
return ecl_eql(x, y);
case t_character:
return (tx == ty) && (ECL_CHAR_CODE(x) == ECL_CHAR_CODE(y));
case t_base_string:

View file

@ -96,8 +96,8 @@ si_write_object_with_circle(cl_object x, cl_object stream, cl_object print_funct
cl_object hash =
cl__make_hash_table(@'eq',
ecl_make_fixnum(1024),
cl_core.rehash_size,
cl_core.rehash_threshold);
ecl_ct_default_rehash_size,
ecl_ct_default_rehash_threshold);
ecl_bds_bind(env, @'si::*circle-counter*', ECL_T);
ecl_bds_bind(env, @'si::*circle-stack*', hash);
si_write_object_with_circle(x, cl_core.null_stream, print_function);

View file

@ -370,6 +370,18 @@ write_frame(cl_object x, cl_object stream)
_ecl_write_unreadable(x, "frame", ecl_make_fixnum(x->frame.size), stream);
}
static void
write_exception(cl_object x, cl_object stream)
{
_ecl_write_unreadable(x, "exception", ECL_NIL, stream);
}
static void
write_module(cl_object x, cl_object stream)
{
_ecl_write_unreadable(x, "module", x->module.name, stream);
}
static void
write_weak_pointer(cl_object x, cl_object stream)
{
@ -480,6 +492,8 @@ static printer dispatch[FREE+1] = {
write_codeblock, /* t_codeblock */
write_foreign, /* t_foreign */
write_frame, /* t_frame */
write_exception, /* t_exception */
write_module, /* t_module */
write_weak_pointer, /* t_weak_pointer */
#ifdef ECL_SSE2
_ecl_write_sse, /* t_sse_pack */

View file

@ -36,11 +36,25 @@
#ifdef ECL_THREADS
# ifdef ECL_WINDOWS_THREADS
# define ecl_process_eq(t1, t2) (GetThreadId(t1) == GetThreadId(t2))
# define ecl_set_process_self(var) \
{ \
HANDLE aux = GetCurrentThread(); \
DuplicateHandle(GetCurrentProcess(), \
aux, \
GetCurrentProcess(), \
&var, \
0, \
FALSE, \
DUPLICATE_SAME_ACCESS); \
}
# define ecl_process_key_t DWORD
# define ecl_process_key_create(key) key = TlsAlloc()
# define ecl_process_get_tls(key) TlsGetValue(key)
# define ecl_process_set_tls(key,val) (TlsSetValue(key,val)!=0)
# else
# define ecl_process_eq(t1, t2) (t1 == t2)
# define ecl_set_process_self(var) (var = pthread_self())
# define ecl_process_key_t static pthread_key_t
# define ecl_process_key_create(key) pthread_key_create(&key, NULL)
# define ecl_process_get_tls(key) pthread_getspecific(key)
@ -79,23 +93,212 @@ ecl_set_process_env(cl_env_ptr env)
cl_env_ptr cl_env_p = NULL;
#endif /* ECL_THREADS */
/* -- Initialiation --------------------------------------------------------- */
#ifdef ECL_THREADS
/* -- Thread local bindings */
static void
init_tl_bindings(cl_object process, cl_env_ptr env)
{
cl_index bindings_size;
cl_object *bindings;
if (Null(process) || Null(process->process.inherit_bindings_p)) {
cl_index idx = 0, size = 256;
bindings_size = size;
bindings = (cl_object *)ecl_malloc(size*sizeof(cl_object*));
for(idx=0; idx<256; idx++) {
bindings[idx] = ECL_NO_TL_BINDING;
}
} else {
cl_env_ptr parent_env = ecl_process_env();
bindings_size = parent_env->bds_stack.tl_bindings_size;
bindings = (cl_object *)ecl_malloc(bindings_size*sizeof(cl_object*));
ecl_copy(bindings, parent_env->bds_stack.tl_bindings, bindings_size*sizeof(cl_object*));
}
env->bds_stack.tl_bindings_size = bindings_size;
env->bds_stack.tl_bindings = bindings;
}
#endif
/* -- Managing the collection of processes ---------------------------------- */
#ifdef ECL_THREADS
/* Run a process in the current system thread. */
cl_env_ptr
ecl_adopt_cpu()
{
cl_env_ptr the_env = ecl_process_env_unsafe();
if (the_env != NULL)
return the_env;
the_env = _ecl_alloc_env(0);
ecl_set_process_env(the_env);
the_env->own_process = ECL_NIL;
ecl_modules_init_env(the_env);
ecl_modules_init_cpu(the_env);
return the_env;
}
void
init_process(void)
ecl_disown_cpu()
{
cl_env_ptr the_env = ecl_process_env_unsafe();
if (the_env == NULL)
return;
ecl_modules_free_cpu(the_env);
ecl_modules_free_env(the_env);
_ecl_dealloc_env(the_env);
}
#ifdef ECL_WINDOWS_THREADS
static DWORD WINAPI
#else
static void *
#endif
thread_entry_point(void *ptr)
{
cl_env_ptr the_env = ecl_cast_ptr(cl_env_ptr, ptr);
cl_object process = the_env->own_process;
/* Setup the environment for the execution of the thread. */
ecl_modules_init_cpu(the_env);
/* Start the user routine */
process->process.entry(0);
ecl_disable_interrupts_env(the_env);
ecl_disown_cpu();
#ifdef ECL_WINDOWS_THREADS
return 1;
#else
return NULL;
#endif
}
/* Run a process in a new system thread. */
cl_env_ptr
ecl_spawn_cpu(cl_object process)
{
cl_env_ptr the_env = ecl_process_env();
cl_env_ptr new_env = NULL;
int code = 0;
/* Allocate and initialize the new cpu env. */
{
new_env = _ecl_alloc_env(the_env);
new_env->trap_fpe_bits = the_env->trap_fpe_bits;
new_env->own_process = process;
process->process.env = new_env;
ecl_modules_init_env(new_env);
}
/* Spawn the thread */
ecl_disable_interrupts_env(the_env);
#if !defined(ECL_WINDOWS_THREADS) && defined(HAVE_SIGPROCMASK)
{
/* Block all asynchronous signals until the thread is completely set up. The
* synchronous signals SIGSEGV and SIGBUS are needed by the gc and and can't
* be blocked. */
sigset_t new, previous;
sigfillset(&new);
sigdelset(&new, SIGSEGV);
sigdelset(&new, SIGBUS);
ecl_sigmask(SIG_BLOCK, &new, &previous);
code = ecl_thread_create(new_env, thread_entry_point);
ecl_sigmask(SIG_SETMASK, &previous, NULL);
}
#else
code = ecl_thread_create(new_env, thread_entry_point);
#endif
/* Deal with the fallout of the thread creation. */
if (code != 0) {
process->process.env = NULL;
ecl_modules_free_env(new_env);
_ecl_dealloc_env(new_env);
}
ecl_enable_interrupts_env(the_env);
return code ? NULL : new_env;
}
#endif
/* -- Module definition (so meta!) ------------------------------------------ */
static cl_object
create_process(void)
{
cl_env_ptr env = cl_core.first_env;
#ifdef ECL_THREADS
ecl_process_key_create(cl_env_key);
ecl_mutex_init(&cl_core.processes_lock, 1);
ecl_mutex_init(&cl_core.global_lock, 1);
ecl_mutex_init(&cl_core.error_lock, 1);
ecl_rwlock_init(&cl_core.global_env_lock);
ecl_mutex_init(&ecl_core.processes_lock, 1);
ecl_mutex_init(&ecl_core.global_lock, 1);
ecl_mutex_init(&ecl_core.error_lock, 1);
ecl_rwlock_init(&ecl_core.global_env_lock);
ecl_core.threads = ecl_make_stack(16);
#endif
ecl_set_process_env(env);
env->default_sigmask = NULL;
env->method_cache = NULL;
env->slot_cache = NULL;
env->interrupt_struct = NULL;
env->disable_interrupts = 1;
return ECL_NIL;
}
static cl_object
init_env_process(cl_env_ptr the_env)
{
#ifdef ECL_THREAD
init_tl_bindings(the_env->own_process, the_env);
#endif
return ECL_NIL;
}
static cl_object
init_cpu_process(cl_env_ptr the_env)
{
#ifdef ECL_THREADS
ecl_thread_t main_thread;
ecl_set_process_self(main_thread);
the_env->thread = main_thread;
#endif
ecl_set_process_env(the_env);
return ECL_NIL;
}
static cl_object
free_cpu_process(cl_env_ptr the_env)
{
#ifdef ECL_WINDOWS_THREADS
CloseHandle(the_env->thread);
#endif
#if 0
/* KLUDGE when we destroy the module in destroy_process, the stack is freed
and threads are dereferenced. It might be that GC will try to pick them up
to run finalizers -- in that case we will still require a process env. */
ecl_set_process_env(NULL);
#endif
return ECL_NIL;
}
static cl_object
free_env_process(cl_env_ptr the_env)
{
#ifdef ECL_THREAD
the_env->own_process = ECL_NIL;
#endif
return ECL_NIL;
}
static cl_object
destroy_process(void)
{
#ifdef ECL_THREADS
ecl_free_stack(ecl_core.threads);
ecl_core.threads = ECL_NIL;
#endif
return ECL_NIL;
}
ecl_def_ct_base_string(str_process, "PROCESS", 7, static, const);
static struct ecl_module module_process = {
.name = str_process,
.create = create_process,
.enable = ecl_module_no_op,
.init_env = init_env_process,
.init_cpu = init_cpu_process,
.free_cpu = free_cpu_process,
.free_env = free_env_process,
.disable = ecl_module_no_op,
.destroy = destroy_process
};
cl_object ecl_module_process = (cl_object)&module_process;

View file

@ -1277,8 +1277,8 @@ patch_sharp(const cl_env_ptr the_env, cl_object x)
} else {
cl_object table =
cl__make_hash_table(@'eq', ecl_make_fixnum(20), /* size */
cl_core.rehash_size,
cl_core.rehash_threshold);
ecl_ct_default_rehash_size,
ecl_ct_default_rehash_threshold);
do {
cl_object pair = ECL_CONS_CAR(pairs);
_ecl_sethash(pair, table, ECL_CONS_CDR(pair));
@ -1718,7 +1718,7 @@ do_read_delimited_list(int d, cl_object in, bool proper_list)
@(return ECL_CODE_CHAR(c));
}
} else if (f == ECL_LISTEN_NO_CHAR) {
@(return @'nil');
@(return ECL_NIL);
}
/* We reach here if there was an EOF */
END_OF_FILE:
@ -1859,8 +1859,8 @@ ecl_readtable_set(cl_object readtable, int c, enum ecl_chattrib cat,
cl_object hash = readtable->readtable.hash;
if (Null(hash)) {
hash = cl__make_hash_table(@'eql', ecl_make_fixnum(128),
cl_core.rehash_size,
cl_core.rehash_threshold);
ecl_ct_default_rehash_size,
ecl_ct_default_rehash_threshold);
readtable->readtable.hash = hash;
}
_ecl_sethash(ECL_CODE_CHAR(c), hash,
@ -1937,8 +1937,8 @@ ecl_invalid_character_p(int c)
c = ecl_char_code(chr);
cat = Null(non_terminating_p)? cat_terminating : cat_non_terminating;
table = cl__make_hash_table(@'eql', ecl_make_fixnum(128),
cl_core.rehash_size,
cl_core.rehash_threshold);
ecl_ct_default_rehash_size,
ecl_ct_default_rehash_threshold);
ecl_readtable_set(readtable, c, cat, table);
@(return ECL_T);
@)

View file

@ -76,6 +76,8 @@ static cl_index object_size[] = {
ROUNDED_SIZE(ecl_codeblock), /* t_codeblock */
ROUNDED_SIZE(ecl_foreign), /* t_foreign */
ROUNDED_SIZE(ecl_stack_frame), /* t_frame */
ROUNDED_SIZE(ecl_exception), /* t_exception */
ROUNDED_SIZE(ecl_module), /* t_module */
ROUNDED_SIZE(ecl_weak_pointer) /* t_weak_pointer */
#ifdef ECL_SSE2
, ROUNDED_SIZE(ecl_sse_pack) /* t_sse_pack */
@ -349,8 +351,8 @@ init_pool(pool_t pool, cl_object root)
ECL_NIL,
ecl_make_fixnum(0));
pool->hash = cl__make_hash_table(@'eql', ecl_make_fixnum(256),
cl_core.rehash_size,
cl_core.rehash_threshold);
ecl_ct_default_rehash_size,
ecl_ct_default_rehash_threshold);
ecl_sethash(root, pool->hash, ecl_make_fixnum(0));
pool->queue = ecl_list1(root);
pool->last = pool->queue;

251
src/c/stack2.d Normal file
View file

@ -0,0 +1,251 @@
/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* vim: set filetype=c tabstop=2 shiftwidth=2 expandtab: */
/*
* stacks.d - runtime, binding, history and frame stacks
*
* Copyright (c) 1984 Taiichi Yuasa and Masami Hagiya
* Copyright (c) 1990 Giuseppe Attardi
* Copyright (c) 2001 Juan Jose Garcia Ripoll
*
* See file 'LICENSE' for the copyright details.
*
*/
#include <ecl/ecl.h>
#include <ecl/ecl-inl.h>
#include <signal.h>
#include <string.h>
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/time.h>
# include <sys/resource.h>
#endif
#include <ecl/nucleus.h>
#include <ecl/ecl-inl.h>
#include <ecl/internal.h>
#include <ecl/stack-resize.h>
/* -- Bindings stack -------------------------------------------------------- */
static ecl_bds_ptr
get_bds_ptr(cl_object x)
{
if (ECL_FIXNUMP(x)) {
cl_env_ptr env = ecl_process_env();
ecl_bds_ptr p = env->bds_stack.org + ecl_fixnum(x);
if (env->bds_stack.org <= p && p <= env->bds_stack.top)
return(p);
}
FEerror("~S is an illegal bds index.", 1, x);
}
cl_object
si_bds_top()
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, ecl_make_fixnum(env->bds_stack.top - env->bds_stack.org));
}
cl_object
si_bds_var(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, get_bds_ptr(arg)->symbol);
}
cl_object
si_bds_val(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
cl_object v = get_bds_ptr(arg)->value;
ecl_return1(env, ((v == OBJNULL || v == ECL_NO_TL_BINDING)? ECL_UNBOUND : v));
}
/* -- Frame stack ----------------------------------------------------------- */
static ecl_frame_ptr
get_frame_ptr(cl_object x)
{
if (ECL_FIXNUMP(x)) {
cl_env_ptr env = ecl_process_env();
ecl_frame_ptr p = env->frs_stack.org + ecl_fixnum(x);
if (env->frs_stack.org <= p && p <= env->frs_stack.top)
return p;
}
FEerror("~S is an illegal frs index.", 1, x);
}
cl_object
si_frs_top()
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, ecl_make_fixnum(env->frs_stack.top - env->frs_stack.org));
}
cl_object
si_frs_bds(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, ecl_make_fixnum(get_frame_ptr(arg)->frs_bds_ndx));
}
cl_object
si_frs_tag(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, get_frame_ptr(arg)->frs_val);
}
cl_object
si_frs_ihs(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, ecl_make_fixnum(get_frame_ptr(arg)->frs_ihs->index));
}
cl_object
si_sch_frs_base(cl_object fr, cl_object ihs)
{
cl_env_ptr env = ecl_process_env();
ecl_frame_ptr x;
cl_index y = ecl_to_size(ihs);
for (x = get_frame_ptr(fr);
x <= env->frs_stack.top && x->frs_ihs->index < y;
x++);
ecl_return1(env, ((x > env->frs_stack.top)
? ECL_NIL
: ecl_make_fixnum(x - env->frs_stack.org)));
}
/* -- Invocation stack ------------------------------------------------------ */
static ecl_ihs_ptr
get_ihs_ptr(cl_index n)
{
cl_env_ptr env = ecl_process_env();
ecl_ihs_ptr p = env->ihs_stack.top;
if (n > p->index)
FEerror("~D is an illegal IHS index.", 1, ecl_make_fixnum(n));
while (n < p->index)
p = p->next;
return p;
}
cl_object
si_ihs_top(void)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, ecl_make_fixnum(env->ihs_stack.top->index));
}
cl_object
si_ihs_prev(cl_object x)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, cl_1M(x));
}
cl_object
si_ihs_next(cl_object x)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, cl_1P(x));
}
cl_object
si_ihs_bds(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, ecl_make_fixnum(get_ihs_ptr(ecl_to_size(arg))->bds));
}
cl_object
si_ihs_fun(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, get_ihs_ptr(ecl_to_size(arg))->function);
}
cl_object
si_ihs_lex(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, get_ihs_ptr(ecl_to_size(arg))->lex_env);
}
cl_object
si_ihs_lcl(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, get_ihs_ptr(ecl_to_size(arg))->lcl_env);
}
/* DEPRECATED backward compatibility with SWANK/SLYNK. --jd 2025-11-17 */
cl_object
si_ihs_env(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, get_ihs_ptr(ecl_to_size(arg))->lcl_env);
}
/* -- Lisp ops on stacks ---------------------------------------------------- */
cl_object
si_set_limit(cl_object type, cl_object limit)
{
cl_env_ptr env = ecl_process_env();
cl_index margin;
if (type == @'ext::frame-stack') {
cl_index current_size = env->frs_stack.top - env->frs_stack.org;
cl_index request_size = ecl_to_size(limit);
if(current_size > request_size)
FEerror("Cannot shrink frame stack below ~D.", 1, limit);
ecl_frs_set_limit(env, request_size);
} else if (type == @'ext::binding-stack') {
cl_index current_size = env->bds_stack.top - env->bds_stack.org;
cl_index request_size = ecl_to_size(limit);
if(current_size > request_size)
FEerror("Cannot shrink binding stack below ~D.", 1, limit);
ecl_bds_set_limit(env, request_size);
} else if (type == @'ext::lisp-stack') {
cl_index current_size = env->run_stack.top - env->run_stack.org;
cl_index request_size = ecl_to_size(limit);
if(current_size > request_size)
FEerror("Cannot shrink lisp stack below ~D.", 1, limit);
ecl_data_stack_set_limit(env, request_size);
} else if (type == @'ext::c-stack') {
cl_index the_size = ecl_to_size(limit);
margin = ecl_option_values[ECL_OPT_C_STACK_SAFETY_AREA];
ecl_cs_set_size(env, the_size + 2*margin);
} else if (type == @'ext::heap-size') {
/*
* size_t can be larger than cl_index, and ecl_to_size()
* creates a fixnum which is too small for size_t on 32-bit.
*/
size_t the_size = (size_t)ecl_to_ulong(limit);
_ecl_set_max_heap_size(the_size);
}
ecl_return1(env, si_get_limit(type));
}
cl_object
si_get_limit(cl_object type)
{
cl_env_ptr env = ecl_process_env();
cl_index output = 0;
if (type == @'ext::frame-stack')
output = env->frs_stack.limit_size;
else if (type == @'ext::binding-stack')
output = env->bds_stack.limit_size;
else if (type == @'ext::lisp-stack')
output = env->run_stack.limit_size;
else if (type == @'ext::c-stack')
output = env->c_stack.limit_size;
else if (type == @'ext::heap-size') {
/* size_t can be larger than cl_index */
ecl_return1(env, ecl_make_unsigned_integer(ecl_core.max_heap_size));
}
ecl_return1(env, ecl_make_unsigned_integer(output));
}

View file

@ -20,6 +20,7 @@
# include <sys/time.h>
# include <sys/resource.h>
#endif
#include <ecl/nucleus.h>
#include <ecl/ecl-inl.h>
#include <ecl/internal.h>
#include <ecl/stack-resize.h>
@ -32,17 +33,11 @@ ecl_cs_init(cl_env_ptr env)
cl_index margin = ecl_option_values[ECL_OPT_C_STACK_SAFETY_AREA];
cl_index new_size = ecl_option_values[ECL_OPT_C_STACK_SIZE];
cl_index max_size = new_size;
#ifdef GBC_BOEHM
struct GC_stack_base base;
if (GC_get_stack_base(&base) == GC_SUCCESS)
env->c_stack.org = (char*)base.mem_base;
else
if (env->c_stack.org == NULL) {
/* Rough estimate. Not very safe. We assume that cl_boot() is invoked from
* the main() routine of the program. */
env->c_stack.org = (char*)(&env);
#else
/* Rough estimate. Not very safe. We assume that cl_boot() is invoked from the
* main() routine of the program. */
env->c_stack.org = (char*)(&env);
#endif
}
#ifdef ECL_CAN_SET_STACK_SIZE
{
struct rlimit rl;
@ -162,9 +157,9 @@ ecl_cs_overflow(void)
else
ecl_internal_error(stack_overflow_msg);
if (env->c_stack.max_size == (cl_index)0 || env->c_stack.size < env->c_stack.max_size)
CEstack_overflow(@'ext::c-stack', ecl_make_fixnum(size), ECL_T);
ecl_cerror(ECL_EX_CS_OVR, ecl_make_fixnum(size), ECL_T);
else
CEstack_overflow(@'ext::c-stack', ecl_make_fixnum(size), ECL_NIL);
ecl_ferror(ECL_EX_CS_OVR, ecl_make_fixnum(size), ECL_NIL);
}
/* -- Data stack ------------------------------------------------------------ */
@ -375,7 +370,7 @@ bds_init(cl_env_ptr env)
margin = ecl_option_values[ECL_OPT_BIND_STACK_SAFETY_AREA];
limit_size = ecl_option_values[ECL_OPT_BIND_STACK_SIZE];
size = limit_size + 2 * margin;
env->bds_stack.org = (ecl_bds_ptr)ecl_malloc(size * sizeof(*env->bds_stack.org));
env->bds_stack.org = (ecl_bds_ptr)ecl_malloc(size * sizeof(cl_object*));
env->bds_stack.top = env->bds_stack.org-1;
env->bds_stack.limit = &env->bds_stack.org[limit_size];
env->bds_stack.size = size;
@ -392,13 +387,14 @@ ecl_bds_overflow(void)
cl_env_ptr env = ecl_process_env();
cl_index margin = ecl_option_values[ECL_OPT_BIND_STACK_SAFETY_AREA];
cl_index size = env->bds_stack.size;
cl_index limit_size = env->bds_stack.limit_size;
ecl_bds_ptr org = env->bds_stack.org;
ecl_bds_ptr last = org + size;
if (env->bds_stack.limit >= last) {
ecl_internal_error(stack_overflow_msg);
}
env->bds_stack.limit += margin;
CEstack_overflow(@'ext::binding-stack', ecl_make_fixnum(size), ECL_T);
ecl_cerror(ECL_EX_BDS_OVR, ecl_make_fixnum(limit_size), ECL_T);
return env->bds_stack.top;
}
@ -440,11 +436,11 @@ ecl_new_binding_index(cl_env_ptr env, cl_object symbol)
cl_object pool;
cl_index new_index = symbol->symbol.binding;
if (new_index == ECL_MISSING_SPECIAL_BINDING) {
pool = ecl_atomic_pop(&cl_core.reused_indices);
pool = ecl_atomic_pop(&ecl_core.reused_indices);
if (!Null(pool)) {
new_index = ecl_fixnum(ECL_CONS_CAR(pool));
} else {
new_index = ecl_atomic_index_incf(&cl_core.last_var_index);
new_index = ecl_atomic_index_incf(&ecl_core.last_var_index);
}
symbol->symbol.binding = new_index;
}
@ -460,7 +456,7 @@ invalid_or_too_large_binding_index(cl_env_ptr env, cl_object s)
}
if (index >= env->bds_stack.tl_bindings_size) {
cl_index osize = env->bds_stack.tl_bindings_size;
cl_index nsize = cl_core.last_var_index * 1.25;
cl_index nsize = ecl_core.last_var_index * 1.25;
cl_object *old_vector = env->bds_stack.tl_bindings;
cl_object *new_vector = ecl_realloc(old_vector,
osize*sizeof(cl_object*),
@ -677,7 +673,7 @@ frs_overflow(void)
ecl_internal_error(stack_overflow_msg);
}
env->frs_stack.limit += margin;
CEstack_overflow(@'ext::frame-stack', ecl_make_fixnum(limit_size), ECL_T);
ecl_cerror(ECL_EX_FRS_OVR, ecl_make_fixnum(limit_size), ECL_T);
}
ecl_frame_ptr
@ -713,239 +709,91 @@ frs_sch (cl_object frame_id)
return(NULL);
}
/* -- Initialization -------------------------------------------------------- */
cl_object
init_stacks(cl_env_ptr the_env)
/* -- Module definition ------------------------------------------------------ */
static cl_object
create_stacks(void)
{
cl_env_ptr the_env = ecl_core.first_env;
#ifdef ECL_THREADS
if (the_env == cl_core.first_env) {
cl_index idx;
cl_object *vector = (cl_object *)ecl_malloc(1024*sizeof(cl_object*));
for(idx=0; idx<1024; idx++) {
vector[idx] = ECL_NO_TL_BINDING;
}
the_env->bds_stack.tl_bindings_size = 1024;
the_env->bds_stack.tl_bindings = vector;
cl_index idx;
cl_object *vector = (cl_object *)ecl_malloc(1024*sizeof(cl_object*));
for(idx=0; idx<1024; idx++) {
vector[idx] = ECL_NO_TL_BINDING;
}
the_env->bds_stack.tl_bindings_size = 1024;
the_env->bds_stack.tl_bindings = vector;
#endif
the_env->c_stack.org = NULL;
return ECL_NIL;
}
static cl_object
enable_stacks(void)
{
return ECL_NIL;
}
static cl_object
init_env_stacks(cl_env_ptr the_env)
{
frs_init(the_env);
bds_init(the_env);
run_init(the_env);
ihs_init(the_env);
/* FIXME ecl_cs_init must be called from the thread entry point at the
beginning to correctly determine the stack base. */
#if 0
cs_init(the_env);
#endif
the_env->c_stack.org = NULL;
return ECL_NIL;
}
cl_object
free_stacks(cl_env_ptr the_env)
static cl_object
init_cpu_stacks(cl_env_ptr the_env)
{
ecl_cs_init(the_env);
return ECL_NIL;
}
static cl_object
free_cpu_stacks(cl_env_ptr the_env)
{
return ECL_NIL;
}
static cl_object
free_env_stacks(cl_env_ptr the_env)
{
#ifdef ECL_THREADS
ecl_free(the_env->bds_stack.tl_bindings);
the_env->bds_stack.tl_bindings_size = 0;
#endif
ecl_free(the_env->run_stack.org);
ecl_free(the_env->bds_stack.org);
ecl_free(the_env->frs_stack.org);
return ECL_NIL;
}
/* -- High level interface -------------------------------------------------- */
void
ecl_unwind(cl_env_ptr env, ecl_frame_ptr fr)
static cl_object
destroy_stacks(void)
{
env->frs_stack.nlj_fr = fr;
ecl_frame_ptr top = env->frs_stack.top;
while (top != fr && top->frs_val != ECL_PROTECT_TAG){
top->frs_val = ECL_DUMMY_TAG;
--top;
}
env->ihs_stack.top = top->frs_ihs;
ecl_bds_unwind(env, top->frs_bds_ndx);
ECL_STACK_UNWIND(env, top->frs_run_ndx);
env->frs_stack.top = top;
ecl_longjmp(env->frs_stack.top->frs_jmpbuf, 1);
/* never reached */
cl_env_ptr the_env = ecl_core.first_env;
#ifdef ECL_THREADS
ecl_free(the_env->bds_stack.tl_bindings);
the_env->bds_stack.tl_bindings_size = 0;
the_env->bds_stack.tl_bindings = NULL;
#endif
return ECL_NIL;
}
cl_index
ecl_progv(cl_env_ptr env, cl_object vars0, cl_object values0)
{
cl_object vars = vars0, values = values0;
cl_index n = env->bds_stack.top - env->bds_stack.org;
for (; LISTP(vars) && LISTP(values); vars = ECL_CONS_CDR(vars)) {
if (Null(vars)) {
return n;
} else {
cl_object var = ECL_CONS_CAR(vars);
if (!ECL_SYMBOLP(var))
FEillegal_variable_name(var);
if (ecl_symbol_type(var) & ecl_stp_constant)
FEbinding_a_constant(var);
if (Null(values)) {
ecl_bds_bind(env, var, OBJNULL);
} else {
ecl_bds_bind(env, var, ECL_CONS_CAR(values));
values = ECL_CONS_CDR(values);
}
}
}
FEerror("Wrong arguments to special form PROGV. Either~%"
"~A~%or~%~A~%are not proper lists",
2, vars0, values0);
}
ecl_def_ct_base_string(str_stacks, "STACKS", 6, static, const);
/* -- Bindings stack -------------------------------------------------------- */
static struct ecl_module module_stacks = {
.name = str_stacks,
.create = create_stacks,
.enable = enable_stacks,
.init_env = init_env_stacks,
.init_cpu = init_cpu_stacks,
.free_cpu = free_cpu_stacks,
.free_env = free_env_stacks,
.disable = ecl_module_no_op,
.destroy = destroy_stacks
};
static ecl_bds_ptr
get_bds_ptr(cl_object x)
{
if (ECL_FIXNUMP(x)) {
cl_env_ptr env = ecl_process_env();
ecl_bds_ptr p = env->bds_stack.org + ecl_fixnum(x);
if (env->bds_stack.org <= p && p <= env->bds_stack.top)
return(p);
}
FEerror("~S is an illegal bds index.", 1, x);
}
cl_object
si_bds_top()
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, ecl_make_fixnum(env->bds_stack.top - env->bds_stack.org));
}
cl_object
si_bds_var(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, get_bds_ptr(arg)->symbol);
}
cl_object
si_bds_val(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
cl_object v = get_bds_ptr(arg)->value;
ecl_return1(env, ((v == OBJNULL || v == ECL_NO_TL_BINDING)? ECL_UNBOUND : v));
}
/* -- Frame stack ----------------------------------------------------------- */
static ecl_frame_ptr
get_frame_ptr(cl_object x)
{
if (ECL_FIXNUMP(x)) {
cl_env_ptr env = ecl_process_env();
ecl_frame_ptr p = env->frs_stack.org + ecl_fixnum(x);
if (env->frs_stack.org <= p && p <= env->frs_stack.top)
return p;
}
FEerror("~S is an illegal frs index.", 1, x);
}
cl_object
si_frs_top()
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, ecl_make_fixnum(env->frs_stack.top - env->frs_stack.org));
}
cl_object
si_frs_bds(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, ecl_make_fixnum(get_frame_ptr(arg)->frs_bds_ndx));
}
cl_object
si_frs_tag(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, get_frame_ptr(arg)->frs_val);
}
cl_object
si_frs_ihs(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, ecl_make_fixnum(get_frame_ptr(arg)->frs_ihs->index));
}
cl_object
si_sch_frs_base(cl_object fr, cl_object ihs)
{
cl_env_ptr env = ecl_process_env();
ecl_frame_ptr x;
cl_index y = ecl_to_size(ihs);
for (x = get_frame_ptr(fr);
x <= env->frs_stack.top && x->frs_ihs->index < y;
x++);
ecl_return1(env, ((x > env->frs_stack.top)
? ECL_NIL
: ecl_make_fixnum(x - env->frs_stack.org)));
}
/* -- Invocation stack ------------------------------------------------------ */
static ecl_ihs_ptr
get_ihs_ptr(cl_index n)
{
cl_env_ptr env = ecl_process_env();
ecl_ihs_ptr p = env->ihs_stack.top;
if (n > p->index)
FEerror("~D is an illegal IHS index.", 1, ecl_make_fixnum(n));
while (n < p->index)
p = p->next;
return p;
}
cl_object
si_ihs_top(void)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, ecl_make_fixnum(env->ihs_stack.top->index));
}
cl_object
si_ihs_prev(cl_object x)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, cl_1M(x));
}
cl_object
si_ihs_next(cl_object x)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, cl_1P(x));
}
cl_object
si_ihs_bds(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, ecl_make_fixnum(get_ihs_ptr(ecl_to_size(arg))->bds));
}
cl_object
si_ihs_fun(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, get_ihs_ptr(ecl_to_size(arg))->function);
}
cl_object
si_ihs_env(cl_object arg)
{
cl_env_ptr env = ecl_process_env();
ecl_return1(env, get_ihs_ptr(ecl_to_size(arg))->lex_env);
}
cl_object ecl_module_stacks = (cl_object)&module_stacks;
/* -- General purpose stack implementation ----------------------------------- */
@ -953,6 +801,7 @@ si_ihs_env(cl_object arg)
cl_object
ecl_make_stack(cl_index size)
{
/* XXX ecl_alloc flags=manual */
cl_object x = ecl_malloc(sizeof(struct ecl_vector));
x->vector.t = t_vector;
x->vector.elttype = ecl_aet_object;
@ -1007,6 +856,31 @@ ecl_stack_push(cl_object self, cl_object elt)
return self;
}
cl_object
ecl_stack_pop(cl_object self)
{
cl_index fillp = self->vector.fillp;
cl_object elt = ECL_NIL;
if (ecl_unlikely(fillp == 0)) {
ecl_internal_error("ecl_stack_pop: stack underflow");
}
elt = self->vector.self.t[fillp-1];
self->vector.self.t[fillp-1] = ECL_NIL;
self->vector.fillp--;
return elt;
}
cl_object
ecl_stack_dup(cl_object self)
{
cl_index fillp = self->vector.fillp;
if (ecl_unlikely(fillp == 0)) {
ecl_internal_error("ecl_stack_dup: empty stack");
}
ecl_stack_push(self, self->vector.self.t[fillp-1]);
return self;
}
cl_object
ecl_stack_del(cl_object self, cl_object elt)
{
@ -1033,64 +907,14 @@ ecl_stack_popu(cl_object self)
return result;
}
/* -- Lisp ops on stacks ---------------------------------------------------- */
cl_object
si_set_limit(cl_object type, cl_object limit)
void
ecl_stack_grow(cl_object self, cl_index n)
{
cl_env_ptr env = ecl_process_env();
cl_index margin;
if (type == @'ext::frame-stack') {
cl_index current_size = env->frs_stack.top - env->frs_stack.org;
cl_index request_size = ecl_to_size(limit);
if(current_size > request_size)
FEerror("Cannot shrink frame stack below ~D.", 1, limit);
ecl_frs_set_limit(env, request_size);
} else if (type == @'ext::binding-stack') {
cl_index current_size = env->bds_stack.top - env->bds_stack.org;
cl_index request_size = ecl_to_size(limit);
if(current_size > request_size)
FEerror("Cannot shrink binding stack below ~D.", 1, limit);
ecl_bds_set_limit(env, request_size);
} else if (type == @'ext::lisp-stack') {
cl_index current_size = env->run_stack.top - env->run_stack.org;
cl_index request_size = ecl_to_size(limit);
if(current_size > request_size)
FEerror("Cannot shrink lisp stack below ~D.", 1, limit);
ecl_data_stack_set_limit(env, request_size);
} else if (type == @'ext::c-stack') {
cl_index the_size = ecl_to_size(limit);
margin = ecl_option_values[ECL_OPT_C_STACK_SAFETY_AREA];
ecl_cs_set_size(env, the_size + 2*margin);
} else if (type == @'ext::heap-size') {
/*
* size_t can be larger than cl_index, and ecl_to_size()
* creates a fixnum which is too small for size_t on 32-bit.
*/
size_t the_size = (size_t)ecl_to_ulong(limit);
_ecl_set_max_heap_size(the_size);
}
ecl_return1(env, si_get_limit(type));
self->vector.fillp += n;
}
cl_object
si_get_limit(cl_object type)
void
ecl_stack_drop(cl_object self, cl_index n)
{
cl_env_ptr env = ecl_process_env();
cl_index output = 0;
if (type == @'ext::frame-stack')
output = env->frs_stack.limit_size;
else if (type == @'ext::binding-stack')
output = env->bds_stack.limit_size;
else if (type == @'ext::lisp-stack')
output = env->run_stack.limit_size;
else if (type == @'ext::c-stack')
output = env->c_stack.limit_size;
else if (type == @'ext::heap-size') {
/* size_t can be larger than cl_index */
ecl_return1(env, ecl_make_unsigned_integer(cl_core.max_heap_size));
}
ecl_return1(env, ecl_make_unsigned_integer(output));
self->vector.fillp -= n;
}

View file

@ -18,6 +18,21 @@
#include <ecl/ecl.h>
#include <ecl/internal.h>
/* FIXME for now we break the dependency chain for NUCL, but later we want to
bring proto-clos into the early runtime and pull clos streams with it. */
#ifdef ECL_NUCL
# undef ECL_CLOS_STREAMS
#endif
static ecl_character
_ecl_char_code(cl_object c)
{
if (ecl_unlikely(!ECL_CHARACTERP(c))) {
ecl_ferror(ECL_EX_BADARG, @[character], c);
}
return ECL_CHAR_CODE(c);
}
#ifdef ECL_CLOS_STREAMS
extern const struct ecl_file_ops clos_stream_ops;
#endif
@ -66,7 +81,7 @@ ecl_stream_dispatch_table(cl_object strm)
}
#endif
if (!ECL_ANSI_STREAM_P(strm))
FEwrong_type_argument(@[stream], strm);
ecl_ferror(ECL_EX_BADARG, @[stream], strm);
return (const struct ecl_file_ops *)strm->stream.ops;
}
@ -117,7 +132,7 @@ ecl_read_char_noeof(cl_object strm)
{
ecl_character c = ecl_read_char(strm);
if (c == EOF)
FEend_of_file(strm);
ecl_ferror(ECL_EX_EOF, strm, ECL_NIL);
return c;
}
@ -249,7 +264,7 @@ cl_object
si_unread_char(cl_object strm, cl_object c)
{
cl_env_ptr the_env = ecl_process_env();
ecl_unread_char(ecl_char_code(c), strm);
ecl_unread_char(_ecl_char_code(c), strm);
ecl_return1(the_env, ECL_NIL);
}
@ -265,7 +280,7 @@ cl_object
si_write_char(cl_object strm, cl_object c)
{
cl_env_ptr the_env = ecl_process_env();
ecl_write_char(ecl_char_code(c), strm);
ecl_write_char(_ecl_char_code(c), strm);
ecl_return1(the_env, c);
}
@ -354,28 +369,25 @@ cl_file_length(cl_object strm)
@(return ecl_file_length(strm));
}
@(defun file-position (file_stream &o position)
cl_object output;
@
if (Null(position)) {
output = ecl_file_position(file_stream);
} else {
if (position == @':start') {
position = ecl_make_fixnum(0);
} else if (position == @':end') {
position = ECL_NIL;
}
output = ecl_file_position_set(file_stream, position);
}
@(return output);
@)
cl_object
cl_file_string_length(cl_object stream, cl_object string)
{
@(return ecl_file_string_length(stream, string));
}
cl_object
si_file_position_get(cl_object strm)
{
@(return ecl_file_position(strm));
}
cl_object
si_file_position_set(cl_object strm, cl_object position)
{
@(return ecl_file_position_set(strm, position));
}
cl_object
cl_input_stream_p(cl_object strm)
{
@ -406,7 +418,7 @@ cl_open_stream_p(cl_object strm)
}
#endif
unlikely_if (!ECL_ANSI_STREAM_P(strm))
FEwrong_type_only_arg(@'open-stream-p', strm, @'stream');
ecl_ferror(ECL_EX_UNSATISFIED, @[output-stream-p], strm);
@(return (strm->stream.closed ? ECL_NIL : ECL_T));
}
@ -429,11 +441,14 @@ cl_stream_external_format(cl_object strm)
else
#endif
unlikely_if (t != t_stream)
FEwrong_type_only_arg(@[stream-external-format], strm, @[stream]);
ecl_ferror4(ECL_EX_BADARG_ONLY, @[stream-external-format], strm, @[stream]);
if (strm->stream.mode == ecl_smm_synonym) {
strm = SYNONYM_STREAM_STREAM(strm);
goto AGAIN;
}
cl_env_ptr the_env = ecl_process_env();
cl_object sym = SYNONYM_STREAM_SYMBOL(strm);
strm = Null(sym) ? sym : ECL_SYM_VAL(the_env, sym);
if(strm==OBJNULL)
ecl_ferror2(ECL_EX_V_UNBND, sym);
goto AGAIN; }
output = strm->stream.format;
@(return output);
}
@ -467,29 +482,3 @@ si_copy_stream(cl_object in, cl_object out, cl_object wait)
ecl_force_output(out);
@(return ((c==EOF) ? ECL_T : ECL_NIL));
}
cl_object
si_file_stream_fd(cl_object s)
{
cl_object ret;
unlikely_if (!ECL_FILE_STREAM_P(s)) {
ecl_not_a_file_stream(s);
}
switch ((enum ecl_smmode)s->stream.mode) {
case ecl_smm_input:
case ecl_smm_output:
case ecl_smm_io:
ret = ecl_make_fixnum(fileno(IO_STREAM_FILE(s)));
break;
case ecl_smm_input_file:
case ecl_smm_output_file:
case ecl_smm_io_file:
ret = ecl_make_fixnum(IO_FILE_DESCRIPTOR(s));
break;
default:
ecl_internal_error("not a file stream");
}
@(return ret);
}

View file

@ -23,52 +23,31 @@
cl_object
ecl_not_a_file_stream(cl_object strm)
{
cl_error(9, @'simple-type-error', @':format-control',
@"~A is not an file stream",
@':format-arguments', cl_list(1, strm),
@':expected-type', @'file-stream',
@':datum', strm);
ecl_ferror(ECL_EX_BADARG, @[file-stream], strm);
}
void
ecl_not_an_input_stream(cl_object strm)
{
cl_error(9, @'simple-type-error', @':format-control',
@"~A is not an input stream",
@':format-arguments', cl_list(1, strm),
@':expected-type',
cl_list(2, @'satisfies', @'input-stream-p'),
@':datum', strm);
ecl_ferror(ECL_EX_UNSATISFIED, @[input-stream-p], strm);
}
void
ecl_not_an_output_stream(cl_object strm)
{
cl_error(9, @'simple-type-error', @':format-control',
@"~A is not an output stream",
@':format-arguments', cl_list(1, strm),
@':expected-type', cl_list(2, @'satisfies', @'output-stream-p'),
@':datum', strm);
ecl_ferror(ECL_EX_UNSATISFIED, @[output-stream-p], strm);
}
static void
not_a_character_stream(cl_object s)
not_a_character_stream(cl_object strm)
{
cl_error(9, @'simple-type-error', @':format-control',
@"~A is not a character stream",
@':format-arguments', cl_list(1, s),
@':expected-type', @'character',
@':datum', cl_stream_element_type(s));
ecl_ferror(ECL_EX_STRM_BADELT, @[character], strm);
}
static void
not_a_binary_stream(cl_object s)
not_a_binary_stream(cl_object strm)
{
cl_error(9, @'simple-type-error', @':format-control',
@"~A is not a binary stream",
@':format-arguments', cl_list(1, s),
@':expected-type', @'integer',
@':datum', cl_stream_element_type(s));
ecl_ferror(ECL_EX_STRM_BADELT, @[integer], strm);
}
/**********************************************************************
@ -235,14 +214,14 @@ ecl_unknown_column(cl_object strm)
static cl_index
closed_stream_read_byte8(cl_object strm, unsigned char *c, cl_index n)
{
FEclosed_stream(strm);
ecl_ferror(ECL_EX_STRM_CLOSED, strm, ECL_NIL);
return 0;
}
static cl_index
closed_stream_write_byte8(cl_object strm, unsigned char *c, cl_index n)
{
FEclosed_stream(strm);
ecl_ferror(ECL_EX_STRM_CLOSED, strm, ECL_NIL);
return 0;
}
@ -268,34 +247,34 @@ closed_stream_unread_byte(cl_object strm, cl_object byte)
static ecl_character
closed_stream_read_char(cl_object strm)
{
FEclosed_stream(strm);
ecl_ferror(ECL_EX_STRM_CLOSED, strm, ECL_NIL);
return 0;
}
static ecl_character
closed_stream_write_char(cl_object strm, ecl_character c)
{
FEclosed_stream(strm);
ecl_ferror(ECL_EX_STRM_CLOSED, strm, ECL_NIL);
return c;
}
static void
closed_stream_unread_char(cl_object strm, ecl_character c)
{
FEclosed_stream(strm);
ecl_ferror(ECL_EX_STRM_CLOSED, strm, ECL_NIL);
}
static int
closed_stream_listen(cl_object strm)
{
FEclosed_stream(strm);
ecl_ferror(ECL_EX_STRM_CLOSED, strm, ECL_NIL);
return 0;
}
static void
closed_stream_clear_input(cl_object strm)
{
FEclosed_stream(strm);
ecl_ferror(ECL_EX_STRM_CLOSED, strm, ECL_NIL);
}
#define closed_stream_clear_output closed_stream_clear_input
@ -305,7 +284,7 @@ closed_stream_clear_input(cl_object strm)
static cl_object
closed_stream_length(cl_object strm)
{
FEclosed_stream(strm);
ecl_ferror(ECL_EX_STRM_CLOSED, strm, ECL_NIL);
}
#define closed_stream_get_position closed_stream_length
@ -313,7 +292,7 @@ closed_stream_length(cl_object strm)
static cl_object
closed_stream_set_position(cl_object strm, cl_object position)
{
FEclosed_stream(strm);
ecl_ferror(ECL_EX_STRM_CLOSED, strm, ECL_NIL);
}
/**********************************************************************
@ -459,4 +438,3 @@ ecl_generic_read_vector(cl_object strm, cl_object data, cl_index start, cl_index
}
return start;
}

View file

@ -194,7 +194,6 @@ const struct ecl_file_ops two_way_ops = {
two_way_close
};
cl_object
cl_make_two_way_stream(cl_object istrm, cl_object ostrm)
{

278
src/c/streams/strm_nucl.c Normal file
View file

@ -0,0 +1,278 @@
/* -- imports ------------------------------------------------------- */
#include <ecl/ecl.h>
#include <ecl/ecl-inl.h>
#include <ecl/internal.h>
#include <ecl/external.h>
#include <ecl/bytecodes.h>
cl_index
not_implemented_byte8(cl_object strm, unsigned char *c, cl_index n)
{
ecl_ferror(ECL_EX_NIY, ECL_NIL, ECL_NIL);
return 0;
}
static cl_index
not_implemented_vector(cl_object strm, cl_object data, cl_index start, cl_index end)
{
ecl_ferror(ECL_EX_NIY, ECL_NIL, ECL_NIL);
return 0;
}
static void
not_implemented_writer(cl_object strm, cl_object c)
{
ecl_ferror(ECL_EX_NIY, ECL_NIL, ECL_NIL);
}
static void
not_implemented_option(cl_object strm)
{
ecl_ferror(ECL_EX_NIY, ECL_NIL, ECL_NIL);
}
static cl_object
not_implemented_setter(cl_object strm, cl_object val)
{
ecl_ferror(ECL_EX_NIY, ECL_NIL, ECL_NIL);
}
static cl_object
not_implemented_reader(cl_object strm)
{
ecl_ferror(ECL_EX_NIY, ECL_NIL, ECL_NIL);
return ECL_NIL;
}
static int
not_implemented_reader_raw(cl_object strm)
{
ecl_ferror(ECL_EX_NIY, ECL_NIL, ECL_NIL);
return 0;
}
static int
not_implemented_writer_raw(cl_object strm, int c)
{
ecl_ferror(ECL_EX_NIY, ECL_NIL, ECL_NIL);
return 0;
}
static void
not_implemented_unread_raw(cl_object strm, int c)
{
ecl_ferror(ECL_EX_NIY, ECL_NIL, ECL_NIL);
}
struct ecl_file_ops stub_io_ops = {
/* Used to implement encodings */
.write_byte8 = not_implemented_byte8,
.read_byte8 = not_implemented_byte8,
/* Binary I/O */
.write_byte = not_implemented_writer,
.read_byte = not_implemented_reader,
/* String I/O */
.read_char = not_implemented_reader_raw,
.write_char = not_implemented_writer_raw,
.unread_char = not_implemented_unread_raw,
.peek_char = not_implemented_reader_raw,
/* Used to implement r/w sequence */
.read_vector = not_implemented_vector,
.write_vector = not_implemented_vector,
/* Stream operations */
.listen = not_implemented_reader_raw,
.clear_input = not_implemented_option,
.clear_output = not_implemented_option,
.finish_output = not_implemented_option,
.force_output = not_implemented_option,
/* Stream appraisal */
.input_p = not_implemented_reader_raw,
.output_p = not_implemented_reader_raw,
.interactive_p = not_implemented_reader_raw,
.element_type = not_implemented_reader,
/* Cursor operations */
.length = not_implemented_reader,
.get_position = not_implemented_reader,
.set_position = not_implemented_setter,
.string_length = not_implemented_setter,
.column = not_implemented_reader_raw,
/* File stream readers */
.pathname = not_implemented_reader,
.truename = not_implemented_reader,
/* Closing the stream (generic_close replaces the dispatch table) */
.close = not_implemented_reader,
};
cl_object
ecl_make_stub_stream(void)
{
cl_object strm = ecl_alloc_stream();
strm->stream.ops = &stub_io_ops;
strm->stream.mode = ecl_smm_other;
return strm;
}
/* Nucl stream is an input stream that implements only operations that are
necessary for I/O (either character or binary). Limitations:
* char === byte === (unsigned-byte 8)
* use C99 streams (fopen, fread, fwrite etc)
* streams are bivalent
* streams are either input or output (io)
* not all stream operations are implemented
Other than that we follow the same implementation strategy as other streams.
~{read,write}_byte8~ are used to churn bytes and {read,write}_{byte,char}
composes them bytes (in our case it is simply byte casting to lisp type). */
static int
nucl_io_error(cl_object strm, const char *s)
{
const cl_env_ptr the_env = ecl_process_env();
volatile int old_errno = errno;
FILE *f = IO_STREAM_FILE(strm);
if (f != NULL) clearerr(f);
ecl_enable_interrupts_env(the_env);
if (old_errno == EINTR)
return 1;
ecl_internal_error("nucl_io_error: something happened!");
}
static cl_index
nucl_r8(cl_object strm, unsigned char *c, cl_index n)
{
FILE *f = IO_STREAM_FILE(strm);
cl_fixnum out = 0;
ecl_disable_interrupts();
do {
out = fread(c, sizeof(char), n, f);
} while (out < n && ferror(f) && nucl_io_error(strm, "fread"));
ecl_enable_interrupts();
return out;
}
static cl_index
nucl_w8(cl_object strm, unsigned char *c, cl_index n)
{
cl_index out;
ecl_disable_interrupts();
do {
out = fwrite(c, sizeof(char), n, IO_STREAM_FILE(strm));
} while (out < n && nucl_io_error(strm, "fwrite"));
ecl_enable_interrupts();
return out;
}
static ecl_character
nucl_read_char(cl_object strm)
{
unsigned char c;
if (!Null(strm->stream.byte_stack)) {
cl_object value = strm->stream.byte_stack;
strm->stream.byte_stack = ECL_NIL;
return ECL_CHAR_CODE(value);
}
if (nucl_r8(strm, &c, 1) < 1) {
return EOF;
}
return c;
}
static cl_object
nucl_read_byte(cl_object strm)
{
unsigned char c;
if (nucl_r8(strm, &c, 1) < 1) {
return ECL_NIL;
}
return ecl_make_fixnum(c);
}
static void
nucl_unread_char(cl_object strm, int ch)
{
strm->stream.byte_stack = ECL_CODE_CHAR(ch);
}
/* FIXME write_char and write_char have different order of args(!) */
/* FIXME write_char and write_byte have different results(!) */
static void
nucl_write_byte(cl_object strm, cl_object byte)
{
unsigned char v = (unsigned char)ecl_fixnum(byte);
nucl_w8(strm, &v, 1);
}
static ecl_character
nucl_write_char(cl_object strm, ecl_character c)
{
unsigned char v = (unsigned char)c;
nucl_w8(strm, &v, 1);
return c;
}
struct ecl_file_ops nucl_io_ops = {
/* Used to implement encodings */
.write_byte8 = nucl_r8,
.read_byte8 = nucl_w8,
/* Binary I/O */
.write_byte = nucl_write_byte,
.read_byte = nucl_read_byte,
/* String I/O */
.read_char = nucl_read_char,
.write_char = nucl_write_char,
.unread_char = nucl_unread_char,
.peek_char = not_implemented_reader_raw,
/* Used to implement r/w sequence */
.read_vector = not_implemented_vector,
.write_vector = not_implemented_vector,
/* Stream operations */
.listen = not_implemented_reader_raw,
.clear_input = not_implemented_option,
.clear_output = not_implemented_option,
.finish_output = not_implemented_option,
.force_output = not_implemented_option,
/* Stream appraisal */
.input_p = not_implemented_reader_raw,
.output_p = not_implemented_reader_raw,
.interactive_p = not_implemented_reader_raw,
.element_type = not_implemented_reader,
/* Cursor operations */
.length = not_implemented_reader,
.get_position = not_implemented_reader,
.set_position = not_implemented_setter,
.string_length = not_implemented_setter,
.column = not_implemented_reader_raw,
/* File stream readers */
.pathname = not_implemented_reader,
.truename = not_implemented_reader,
/* Closing the stream (generic_close replaces the dispatch table) */
.close = not_implemented_reader,
};
cl_object
ecl_make_nucl_stream(FILE *f)
{
cl_object strm = ecl_alloc_stream();
/* ecl_make_stream_from_FILE() */
strm->stream.mode = ecl_smm_other;
strm->stream.closed = 0;
strm->stream.column = 0;
strm->stream.last_op = 0;
strm->stream.ops = ecl_duplicate_dispatch_table(&nucl_io_ops);
strm->stream.byte_stack = ECL_NIL;
IO_STREAM_FILENAME(strm) = ECL_NIL;
IO_STREAM_FILE(strm) = f;
#if 0 /* currently we don't do formatting */
si_set_finalizer(stream, ECL_T); /* calls cl_close */
/* ecl_set_stream_elt_type() */
stream->stream.flags = ECL_STREAM_DEFAULT_FORMAT;
IO_STREAM_ELT_TYPE(stream) = @'base-char';
stream->stream.format = @':pass-through';
stream->stream.encoder = passthrough_encoder;
stream->stream.decoder = passthrough_decoder;
#endif
return strm;
}

View file

@ -159,7 +159,7 @@ ecl_cmp_symbol_value(cl_env_ptr the_env, cl_object s)
#ifndef ECL_FINAL
/* Symbols are not initialized yet. This test is issued only during ECL
compilation to ensure, that we have no early references in the core. */
if(cl_num_symbols_in_core < 3) {
if(cl_num_symbols_in_core < 2) {
ecl_internal_error("SYMBOL-VALUE: symbols are not initialized yet.");
}
#endif

View file

@ -102,13 +102,11 @@ cl_symbol_initializer
cl_symbols[] = {
{"NIL" ECL_FUN(NULL, NULL, -1) ECL_VAR(CL_ORDINARY, OBJNULL)},
{"T" ECL_FUN(NULL, NULL, -1) ECL_VAR(CL_ORDINARY, OBJNULL)},
{SYS_ "UNBOUND" ECL_FUN("si_unbound", si_unbound, 0) ECL_VAR(SI_CONSTANT, ECL_UNBOUND)},
{SYS_ "PROTECT-TAG" ECL_FUN(NULL, NULL, -1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "DUMMY-TAG" ECL_FUN(NULL, NULL, -1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "*RESTART-CLUSTERS*" ECL_FUN(NULL, NULL, -1) ECL_VAR(SI_SPECIAL, ECL_NIL)},
{SYS_ "*HANDLER-CLUSTERS*" ECL_FUN(NULL, NULL, -1) ECL_VAR(SI_SPECIAL, ECL_NIL)},
{EXT_ "*INTERRUPTS-ENABLED*" ECL_FUN(NULL, NULL, 1) ECL_VAR(EXT_SPECIAL, ECL_T)},
{SYS_ "%ESCAPE" ECL_FUN("ecl_escape", ecl_escape, 1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "%SIGNAL" ECL_FUN("ecl_signal", ecl_signal, 3) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "EXCEPTION-HANDLER" ECL_FUN("ecl_exception_handler", ecl_exception_handler, 1) ECL_VAR(SI_ORDINARY, OBJNULL)},
/* LISP PACKAGE */
{"&ALLOW-OTHER-KEYS" ECL_FUN(NULL, NULL, -1) ECL_VAR(CL_ORDINARY, OBJNULL)},
@ -1189,6 +1187,8 @@ cl_symbols[] = {
{SYS_ "EXPAND-DEFMACRO" ECL_FUN(NULL, NULL, -1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "FILE-COLUMN" ECL_FUN("si_file_column", si_file_column, 1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{EXT_ "FILE-KIND" ECL_FUN("si_file_kind", si_file_kind, 2) ECL_VAR(EXT_ORDINARY, OBJNULL)},
{SYS_ "FILE-POSITION-GET" ECL_FUN("si_file_position_get", si_file_position_get, 1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "FILE-POSITION-SET" ECL_FUN("si_file_position_set", si_file_position_set, 2) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "FILL-POINTER-SET" ECL_FUN("si_fill_pointer_set", si_fill_pointer_set, 2) ECL_VAR(SI_ORDINARY, OBJNULL)},
{EXT_ "FILE-STREAM-FD" ECL_FUN("si_file_stream_fd", si_file_stream_fd, 1) ECL_VAR(EXT_ORDINARY, OBJNULL)},
{EXT_ "MAKE-STREAM-FROM-FD" ECL_FUN(NULL, NULL, -1) ECL_VAR(EXT_ORDINARY, OBJNULL)},
@ -1215,6 +1215,8 @@ cl_symbols[] = {
{SYS_ "HASH-TABLE-ITERATOR" ECL_FUN("si_hash_table_iterator", si_hash_table_iterator, 1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "IHS-BDS" ECL_FUN("si_ihs_bds", si_ihs_bds, 1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "IHS-ENV" ECL_FUN("si_ihs_env", si_ihs_env, 1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "IHS-LEX" ECL_FUN("si_ihs_lex", si_ihs_lex, 1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "IHS-LCL" ECL_FUN("si_ihs_lcl", si_ihs_lcl, 1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "IHS-FUN" ECL_FUN("si_ihs_fun", si_ihs_fun, 1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "IHS-NEXT" ECL_FUN("si_ihs_next", si_ihs_next, 1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "IHS-PREV" ECL_FUN("si_ihs_prev", si_ihs_prev, 1) ECL_VAR(SI_ORDINARY, OBJNULL)},
@ -1355,7 +1357,6 @@ cl_symbols[] = {
{KEY_ "ADJUSTABLE" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)},
{KEY_ "ABORT" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)},
{KEY_ "ABSOLUTE" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)},
{KEY_ "ALLOW-OTHER-KEYS" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)},
{KEY_ "APPEND" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)},
{KEY_ "ARRAY" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)},
{KEY_ "BACK" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)},
@ -1845,6 +1846,8 @@ cl_symbols[] = {
{SYS_ "CODE-BLOCK" ECL_FUN(NULL, NULL, -1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "EXCEPTION" ECL_FUN(NULL, NULL, -1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "MODULE" ECL_FUN(NULL, NULL, -1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "FRAME" ECL_FUN(NULL, NULL, -1) ECL_VAR(SI_ORDINARY, OBJNULL)},
{SYS_ "APPLY-FROM-STACK-FRAME" ECL_FUN("si_apply_from_stack_frame", si_apply_from_stack_frame, 2) ECL_VAR(SI_ORDINARY, OBJNULL)},

View file

@ -31,111 +31,25 @@
# include <sched.h>
#endif
/* -- Macros -------------------------------------------------------- */
#ifdef ECL_WINDOWS_THREADS
# define ecl_process_eq(t1, t2) (GetThreadId(t1) == GetThreadId(t2))
# define ecl_set_process_self(var) \
{ \
HANDLE aux = GetCurrentThread(); \
DuplicateHandle(GetCurrentProcess(), \
aux, \
GetCurrentProcess(), \
&var, \
0, \
FALSE, \
DUPLICATE_SAME_ACCESS); \
}
#else
# define ecl_process_eq(t1, t2) (t1 == t2)
# define ecl_set_process_self(var) (var = pthread_self())
#endif /* ECL_WINDOWS_THREADS */
/* -- Core ---------------------------------------------------------- */
static void
extend_process_vector()
{
cl_object v = cl_core.processes;
cl_index new_size = v->vector.dim + v->vector.dim/2;
cl_env_ptr the_env = ecl_process_env();
ECL_WITH_NATIVE_LOCK_BEGIN(the_env, &cl_core.processes_lock) {
cl_object other = cl_core.processes;
if (new_size > other->vector.dim) {
cl_object new = si_make_vector(ECL_T,
ecl_make_fixnum(new_size),
ecl_make_fixnum(other->vector.fillp),
ECL_NIL, ECL_NIL, ECL_NIL);
ecl_copy_subarray(new, 0, other, 0, other->vector.dim);
cl_core.processes = new;
}
} ECL_WITH_NATIVE_LOCK_END;
}
static void
ecl_list_process(cl_object process)
{
cl_env_ptr the_env = ecl_process_env();
bool ok = 0;
do {
ECL_WITH_NATIVE_LOCK_BEGIN(the_env, &cl_core.processes_lock) {
cl_object vector = cl_core.processes;
cl_index size = vector->vector.dim;
cl_index ndx = vector->vector.fillp;
if (ndx < size) {
vector->vector.self.t[ndx++] = process;
vector->vector.fillp = ndx;
ok = 1;
}
} ECL_WITH_NATIVE_LOCK_END;
if (ok) break;
extend_process_vector();
} while (1);
}
/* Must be called with disabled interrupts to prevent race conditions
* in thread_cleanup */
static void
ecl_unlist_process(cl_object process)
{
ecl_mutex_lock(&cl_core.processes_lock);
cl_object vector = cl_core.processes;
cl_index i;
for (i = 0; i < vector->vector.fillp; i++) {
if (vector->vector.self.t[i] == process) {
vector->vector.fillp--;
do {
vector->vector.self.t[i] =
vector->vector.self.t[i+1];
} while (++i < vector->vector.fillp);
break;
}
}
ecl_mutex_unlock(&cl_core.processes_lock);
}
static cl_object
ecl_process_list()
{
cl_env_ptr the_env = ecl_process_env();
cl_object output = ECL_NIL;
ECL_WITH_NATIVE_LOCK_BEGIN(the_env, &cl_core.processes_lock) {
cl_object vector = cl_core.processes;
cl_object *data = vector->vector.self.t;
cl_index i;
for (i = 0; i < vector->vector.fillp; i++) {
cl_object p = data[i];
if (p != ECL_NIL)
output = ecl_cons(p, output);
}
ECL_WITH_NATIVE_LOCK_BEGIN(the_env, &ecl_core.processes_lock) {
loop_across_stack_fifo(_env, ecl_core.threads) {
cl_env_ptr env = ecl_cast_ptr(cl_env_ptr, _env);
cl_object p = env->own_process;
output = ecl_cons(p, output);
} end_loop_across_stack();
} ECL_WITH_NATIVE_LOCK_END;
return output;
}
/* -- Environment --------------------------------------------------- */
extern void ecl_init_env(struct cl_env_struct *env);
cl_object
mp_current_process(void)
{
@ -151,27 +65,62 @@ assert_type_process(cl_object o)
FEwrong_type_argument(@[mp::process], o);
}
static void
thread_cleanup(void *aux)
static cl_object
run_process(cl_narg narg, ...)
{
/* This routine performs some cleanup before a thread is completely
* killed. For instance, it has to remove the associated process
* object from the list, an it has to dealloc some memory.
/* Upon entering this routine the process environment is set up, the process
* phase is ECL_PROCESS_BOOTING, signals are disabled in the environment and
* the communication interrupt is disabled (sigmasked).
*
* NOTE: thread_cleanup() does not provide enough "protection". In
* order to ensure that all UNWIND-PROTECT forms are properly
* executed, never use pthread_cancel() to kill a process, but
* rather use the lisp functions mp_interrupt_process() and
* mp_process_kill().
* This process will not receive signals that originate from other processes.
* Furthermore, we expect not to get any other interrupts (SIGSEGV, SIGFPE) if
* we do things right.
*/
cl_object process = (cl_object)aux;
cl_env_ptr env = process->process.env;
cl_env_ptr the_env = ecl_process_env();
cl_object process = the_env->own_process;
cl_object fun = process->process.function;
cl_object args = process->process.args;
cl_object output = ECL_NIL;
/* Entry barrier. enable_process releases this lock before exit. */
ecl_mutex_lock(&process->process.start_stop_lock);
/* Execute the code. The CATCH_ALL point is the destination provides us with
* an elegant way to exit the thread: we just do an unwind up to frs_top. */
ECL_CATCH_ALL_BEGIN(the_env) {
#ifdef HAVE_SIGPROCMASK
{
sigset_t *new = (sigset_t*)the_env->default_sigmask;
ecl_sigmask(SIG_SETMASK, new, NULL);
}
#endif
process->process.phase = ECL_PROCESS_ACTIVE;
ecl_mutex_unlock(&process->process.start_stop_lock);
si_trap_fpe(@'last', ECL_T);
ecl_enable_interrupts_env(the_env);
ecl_bds_bind(the_env, @'mp::*current-process*', process);
ECL_RESTART_CASE_BEGIN(the_env, @'abort') {
the_env->values[0] = cl_apply(2, fun, args);
int i = the_env->nvalues;
while (i--) {
output = CONS(the_env->values[i], output);
}
process->process.exit_values = output;
} ECL_RESTART_CASE(1,args) {
/* ABORT restart. */
process->process.exit_values = args;
} ECL_RESTART_CASE_END;
/* This routine performs some cleanup before a thread is finished. Note that
it does not provide enough protection -- in order to ensure that all
UNWIND-PROTECT forms are properly executed, enver use the function
pthread_cancel() to kill a process, but rather use the lisp functions
mp_interrupt_process() and mp_process_kill(). */
ecl_bds_unwind1(the_env);
} ECL_CATCH_ALL_END;
ecl_disable_interrupts_env(the_env);
/* The following flags will disable all interrupts. */
if (env) {
ecl_disable_interrupts_env(env);
ecl_clear_bignum_registers(env);
}
ecl_mutex_lock(&process->process.start_stop_lock);
process->process.phase = ECL_PROCESS_EXITING;
#ifdef HAVE_SIGPROCMASK
@ -180,137 +129,30 @@ thread_cleanup(void *aux)
sigset_t new[1];
sigemptyset(new);
sigaddset(new, ecl_option_values[ECL_OPT_THREAD_INTERRUPT_SIGNAL]);
pthread_sigmask(SIG_BLOCK, new, NULL);
ecl_sigmask(SIG_BLOCK, new, NULL);
}
#endif
process->process.env = NULL;
ecl_unlist_process(process);
#ifdef ECL_WINDOWS_THREADS
CloseHandle(process->process.thread);
#endif
ecl_set_process_env(NULL);
if (env) _ecl_dealloc_env(env);
process->process.phase = ECL_PROCESS_INACTIVE;
ecl_cond_var_broadcast(&process->process.exit_barrier);
ecl_mutex_unlock(&process->process.start_stop_lock);
}
#ifdef ECL_WINDOWS_THREADS
static DWORD WINAPI
#else
static void *
#endif
thread_entry_point(void *arg)
{
cl_object process = (cl_object)arg;
cl_env_ptr env = process->process.env;
/*
* Upon entering this routine
* process.env = our environment for lisp
* process.phase = ECL_PROCESS_BOOTING
* signals are disabled in the environment
* the communication interrupt is disabled (sigmasked)
*
* This process will not receive signals that originate from
* other processes. Furthermore, we expect not to get any
* other interrupts (SIGSEGV, SIGFPE) if we do things right.
*/
/* 1) Setup the environment for the execution of the thread */
ecl_set_process_env(env = process->process.env);
#ifndef ECL_WINDOWS_THREADS
pthread_cleanup_push(thread_cleanup, (void *)process);
#endif
ecl_cs_init(env);
ecl_mutex_lock(&process->process.start_stop_lock);
/* 2) Execute the code. The CATCH_ALL point is the destination
* provides us with an elegant way to exit the thread: we just
* do an unwind up to frs_top.
*/
ECL_CATCH_ALL_BEGIN(env) {
#ifdef HAVE_SIGPROCMASK
{
sigset_t *new = (sigset_t*)env->default_sigmask;
pthread_sigmask(SIG_SETMASK, new, NULL);
}
#endif
process->process.phase = ECL_PROCESS_ACTIVE;
ecl_mutex_unlock(&process->process.start_stop_lock);
ecl_enable_interrupts_env(env);
si_trap_fpe(@'last', ECL_T);
ecl_bds_bind(env, @'mp::*current-process*', process);
ECL_RESTART_CASE_BEGIN(env, @'abort') {
env->values[0] = cl_apply(2, process->process.function,
process->process.args);
{
cl_object output = ECL_NIL;
int i = env->nvalues;
while (i--) {
output = CONS(env->values[i], output);
}
process->process.exit_values = output;
}
} ECL_RESTART_CASE(1,args) {
/* ABORT restart. */
process->process.exit_values = args;
} ECL_RESTART_CASE_END;
ecl_bds_unwind1(env);
} ECL_CATCH_ALL_END;
/* 4) If everything went right, we should be exiting the thread
* through this point. thread_cleanup is automatically invoked
* marking the process as inactive.
*/
#ifdef ECL_WINDOWS_THREADS
thread_cleanup(process);
return 1;
#else
pthread_cleanup_pop(1);
return NULL;
#endif
}
static void
init_tl_bindings(cl_object process, cl_env_ptr env)
{
cl_index bindings_size;
cl_object *bindings;
if (Null(process->process.inherit_bindings_p)) {
cl_index idx = 0, size = 256;
bindings_size = size;
bindings = (cl_object *)ecl_malloc(size*sizeof(cl_object*));
for(idx=0; idx<256; idx++) {
bindings[idx] = ECL_NO_TL_BINDING;
}
} else {
cl_env_ptr parent_env = ecl_process_env();
bindings_size = parent_env->bds_stack.tl_bindings_size;
bindings = (cl_object *)ecl_malloc(bindings_size*sizeof(cl_object*));
ecl_copy(bindings, parent_env->bds_stack.tl_bindings, bindings_size*sizeof(cl_object*));
}
env->bds_stack.tl_bindings_size = bindings_size;
env->bds_stack.tl_bindings = bindings;
return the_env->values[0];
}
static cl_object
alloc_process(cl_object name, cl_object initial_bindings_p)
{
cl_env_ptr env = ecl_process_env();
cl_object process = ecl_alloc_object(t_process), array;
cl_index bindings_size;
cl_object* bindings;
cl_object process = ecl_alloc_object(t_process);
process->process.phase = ECL_PROCESS_INACTIVE;
process->process.exit_values = ECL_NIL;
process->process.entry = run_process;
process->process.name = name;
process->process.function = ECL_NIL;
process->process.args = ECL_NIL;
process->process.interrupt = ECL_NIL;
process->process.inherit_bindings_p = Null(initial_bindings_p)? ECL_T : ECL_NIL;
process->process.exit_values = ECL_NIL;
process->process.env = NULL;
process->process.woken_up = ECL_NIL;
process->process.inherit_bindings_p = Null(initial_bindings_p)? ECL_T : ECL_NIL;
ecl_disable_interrupts_env(env);
ecl_mutex_init(&process->process.start_stop_lock, TRUE);
ecl_cond_var_init(&process->process.exit_barrier);
@ -322,87 +164,49 @@ alloc_process(cl_object name, cl_object initial_bindings_p)
bool
ecl_import_current_thread(cl_object name, cl_object bindings)
{
struct cl_env_struct env_aux[1];
cl_object process;
ecl_thread_t current;
cl_env_ptr env;
int registered;
struct GC_stack_base stack;
ecl_set_process_self(current);
#ifdef GBC_BOEHM
GC_get_stack_base(&stack);
switch (GC_register_my_thread(&stack)) {
case GC_SUCCESS:
registered = 1;
break;
case GC_DUPLICATE:
/* Thread was probably created using the GC hooks for thread creation. */
registered = 0;
break;
default:
cl_env_ptr the_env;
if (ecl_process_env_unsafe() != NULL)
return 0;
}
#endif
{
cl_object processes = cl_core.processes;
cl_index i, size;
for (i = 0, size = processes->vector.fillp; i < size; i++) {
cl_object p = processes->vector.self.t[i];
if (!Null(p) && ecl_process_eq(p->process.thread, current)) {
return 0;
}
}
}
/* We need a fake env to allow for interrupts blocking and to set up
* frame stacks or other stuff which may be needed by alloc_process
* and ecl_list_process. Since the fake env is allocated on the stack,
* we can safely store pointers to memory allocated by the gc there. */
memset(env_aux, 0, sizeof(*env_aux));
env_aux->disable_interrupts = 1;
env_aux->interrupt_struct = ecl_alloc_unprotected(sizeof(*env_aux->interrupt_struct));
env_aux->interrupt_struct->pending_interrupt = ECL_NIL;
ecl_mutex_init(&env_aux->interrupt_struct->signal_queue_lock, FALSE);
env_aux->interrupt_struct->signal_queue = ECL_NIL;
ecl_set_process_env(env_aux);
ecl_init_env(env_aux);
ecl_module_gc->module.disable();
the_env = ecl_adopt_cpu();
ecl_module_gc->module.enable();
ecl_enable_interrupts_env(the_env);
/* Allocate real environment, link it together with process */
env = _ecl_alloc_env(0);
process = alloc_process(name, ECL_NIL);
process->process.env = env;
process->process.env = the_env;
process->process.phase = ECL_PROCESS_BOOTING;
process->process.thread = current;
/* Copy initial bindings from process to the fake environment */
env_aux->cleanup = registered;
init_tl_bindings(process, env_aux);
/* Switch over to the real environment */
memcpy(env, env_aux, sizeof(*env));
env->own_process = process;
ecl_set_process_env(env);
ecl_list_process(process);
ecl_enable_interrupts_env(env);
the_env->own_process = process;
process->process.phase = ECL_PROCESS_ACTIVE;
ecl_bds_bind(env, @'mp::*current-process*', process);
ecl_bds_bind(the_env, @'mp::*current-process*', process);
return 1;
}
void
ecl_release_current_thread(void)
{
cl_env_ptr env = ecl_process_env();
int cleanup = env->cleanup;
cl_object own_process = env->own_process;
thread_cleanup(own_process);
#ifdef GBC_BOEHM
if (cleanup) {
GC_unregister_my_thread();
cl_object process;
cl_env_ptr the_env = ecl_process_env_unsafe();
if (the_env == NULL)
return;
process = the_env->own_process;
ecl_mutex_lock(&process->process.start_stop_lock);
process->process.env = NULL;
process->process.phase = ECL_PROCESS_EXITING;
ecl_disown_cpu();
#ifdef HAVE_SIGPROCMASK
/* ...but we might get stray signals. */
{
sigset_t new[1];
sigemptyset(new);
sigaddset(new, ecl_option_values[ECL_OPT_THREAD_INTERRUPT_SIGNAL]);
ecl_sigmask(SIG_BLOCK, new, NULL);
}
#endif
process->process.phase = ECL_PROCESS_INACTIVE;
ecl_cond_var_broadcast(&process->process.exit_barrier);
ecl_mutex_unlock(&process->process.start_stop_lock);
}
@(defun mp::make-process (&key name ((:initial-bindings initial_bindings_p) ECL_T))
@ -495,109 +299,33 @@ mp_process_yield(void)
cl_object
mp_process_enable(cl_object process)
{
/* process_env and ok are changed after the setjmp call in
* ECL_UNWIND_PROTECT_BEGIN, so they need to be declared volatile */
volatile cl_env_ptr process_env = NULL;
cl_env_ptr the_env = ecl_process_env();
volatile int ok = 1;
ECL_UNWIND_PROTECT_BEGIN(the_env) {
/* Try to gain exclusive access to the process. This prevents two
* concurrent calls to process-enable from different threads on
* the same process */
ecl_mutex_lock(&process->process.start_stop_lock);
/* Ensure that the process is inactive. */
if (process->process.phase != ECL_PROCESS_INACTIVE) {
FEerror("Cannot enable the running process ~A.", 1, process);
}
ok = 0;
process->process.phase = ECL_PROCESS_BOOTING;
process->process.parent = mp_current_process();
process->process.trap_fpe_bits =
process->process.parent->process.env->trap_fpe_bits;
/* Link environment and process together */
process_env = _ecl_alloc_env(the_env);
process_env->own_process = process;
process->process.env = process_env;
/* Immediately list the process such that its environment is
* marked by the gc when its contents are allocated */
ecl_list_process(process);
/* Now we can safely allocate memory for the environment contents
* and store pointers to it in the environment */
ecl_init_env(process_env);
process_env->trap_fpe_bits = process->process.trap_fpe_bits;
init_tl_bindings(process, process_env);
ecl_disable_interrupts_env(the_env);
#ifdef ECL_WINDOWS_THREADS
{
HANDLE code;
DWORD threadId;
code = (HANDLE)CreateThread(NULL, 0, thread_entry_point, process, 0, &threadId);
ok = (process->process.thread = code) != NULL;
}
#else
{
int code;
pthread_attr_t pthreadattr;
pthread_attr_init(&pthreadattr);
pthread_attr_setdetachstate(&pthreadattr, PTHREAD_CREATE_DETACHED);
/*
* Block all asynchronous signals until the thread is completely
* set up. The synchronous signals SIGSEGV and SIGBUS are needed
* by the gc and thus can't be blocked.
*/
#ifdef HAVE_SIGPROCMASK
{
sigset_t new, previous;
sigfillset(&new);
sigdelset(&new, SIGSEGV);
sigdelset(&new, SIGBUS);
pthread_sigmask(SIG_BLOCK, &new, &previous);
code = pthread_create(&process->process.thread, &pthreadattr,
thread_entry_point, process);
pthread_sigmask(SIG_SETMASK, &previous, NULL);
}
#else
code = pthread_create(&process->process.thread, &pthreadattr,
thread_entry_point, process);
#endif
ok = (code == 0);
}
#endif
ecl_enable_interrupts_env(the_env);
} ECL_UNWIND_PROTECT_THREAD_SAFE_EXIT {
if (!ok) {
/* INV: interrupts are already disabled through thread safe
* unwind-protect */
ecl_unlist_process(process);
process->process.phase = ECL_PROCESS_INACTIVE;
/* Alert possible waiting processes. */
ecl_cond_var_broadcast(&process->process.exit_barrier);
process->process.env = NULL;
if (process_env != NULL)
_ecl_dealloc_env(process_env);
}
/* Unleash the thread */
cl_env_ptr process_env = NULL;
/* Try to gain exclusive access to the process. This prevents two concurrent
* calls to process-enable from different threads on the same process */
ecl_mutex_lock(&process->process.start_stop_lock);
/* Ensure that the process is inactive. */
if (process->process.phase != ECL_PROCESS_INACTIVE) {
ecl_mutex_unlock(&process->process.start_stop_lock);
} ECL_UNWIND_PROTECT_THREAD_SAFE_END;
@(return (ok? process : ECL_NIL));
FEerror("Cannot enable the running process ~A.", 1, process);
}
process->process.phase = ECL_PROCESS_BOOTING;
/* Spawn the thread (allocates the environment)*/
process_env = ecl_spawn_cpu(process);
if (process_env == NULL) {
process->process.phase = ECL_PROCESS_INACTIVE;
ecl_cond_var_broadcast(&process->process.exit_barrier);
}
/* Unleash the thread */
ecl_mutex_unlock(&process->process.start_stop_lock);
ecl_return1(the_env, (process_env ? process : ECL_NIL));
}
cl_object
mp_exit_process(void)
{
/* We simply undo the whole of the frame stack. This brings up
back to the thread entry point, going through all possible
UNWIND-PROTECT.
*/
/* We simply undo the whole of the frame stack. This brings up back to the
thread entry point, going through all possible UNWIND-PROTECT. */
const cl_env_ptr the_env = ecl_process_env();
ecl_unwind(the_env, the_env->frs_stack.org);
/* Never reached */
@ -628,8 +356,9 @@ mp_process_active_p(cl_object process)
cl_object
mp_process_whostate(cl_object process)
{
const cl_env_ptr the_env = ecl_process_env();
assert_type_process(process);
@(return (cl_core.null_string));
ecl_return1(the_env, ecl_ct_null_string);
}
cl_object
@ -667,8 +396,7 @@ mp_process_run_function(cl_narg narg, cl_object name, cl_object function, ...)
ecl_va_start(args, function, narg, 2);
rest = cl_grab_rest_args(args);
ecl_va_end(args);
cl_apply(4, @'mp::process-preset', process, function,
rest);
cl_apply(4, @'mp::process-preset', process, function, rest);
return mp_process_enable(process);
}
@ -701,8 +429,8 @@ mp_get_sigmask(void)
sigset_t *mask_ptr = (sigset_t*)data->vector.self.b8;
sigset_t no_signals;
sigemptyset(&no_signals);
if (pthread_sigmask(SIG_BLOCK, &no_signals, mask_ptr))
FElibc_error("MP:GET-SIGMASK failed in a call to pthread_sigmask", 0);
if (ecl_sigmask(SIG_BLOCK, &no_signals, mask_ptr))
FElibc_error("MP:GET-SIGMASK failed in a call to ecl_sigmask", 0);
@(return data);
}
@ -710,8 +438,8 @@ static cl_object
mp_set_sigmask(cl_object data)
{
sigset_t *mask_ptr = (sigset_t*)data->vector.self.b8;
if (pthread_sigmask(SIG_SETMASK, mask_ptr, NULL))
FElibc_error("MP:SET-SIGMASK failed in a call to pthread_sigmask", 0);
if (ecl_sigmask(SIG_SETMASK, mask_ptr, NULL))
FElibc_error("MP:SET-SIGMASK failed in a call to ecl_sigmask", 0);
@(return data);
}
#endif
@ -721,8 +449,8 @@ mp_block_signals(void)
{
#ifdef ECL_WINDOWS_THREADS
cl_env_ptr the_env = ecl_process_env();
cl_object previous = ecl_cmp_symbol_value(the_env, @'ext::*interrupts-enabled*');
ECL_SETQ(the_env, @'ext::*interrupts-enabled*', ECL_NIL);
cl_object previous = ecl_cmp_symbol_value(the_env, ECL_INTERRUPTS_ENABLED);
ECL_SETQ(the_env, ECL_INTERRUPTS_ENABLED, ECL_NIL);
@(return previous);
#else
cl_object previous = mp_get_sigmask();
@ -732,8 +460,8 @@ mp_block_signals(void)
* can thus never be blocked */
sigdelset(&all_signals, SIGSEGV);
sigdelset(&all_signals, SIGBUS);
if (pthread_sigmask(SIG_SETMASK, &all_signals, NULL))
FElibc_error("MP:BLOCK-SIGNALS failed in a call to pthread_sigmask",0);
if (ecl_sigmask(SIG_SETMASK, &all_signals, NULL))
FElibc_error("MP:BLOCK-SIGNALS failed in a call to ecl_sigmask",0);
@(return previous);
#endif
}
@ -743,7 +471,7 @@ mp_restore_signals(cl_object sigmask)
{
#ifdef ECL_WINDOWS_THREADS
cl_env_ptr the_env = ecl_process_env();
ECL_SETQ(the_env, @'ext::*interrupts-enabled*', sigmask);
ECL_SETQ(the_env, ECL_INTERRUPTS_ENABLED, sigmask);
ecl_check_pending_interrupts(the_env);
@(return sigmask);
#else
@ -751,37 +479,75 @@ mp_restore_signals(cl_object sigmask)
#endif
}
/* -- Initialization ------------------------------------------------ */
/* -- Module definition --------------------------------------------- */
void
init_threads()
{
cl_env_ptr the_env = ecl_process_env();
cl_object process;
ecl_thread_t main_thread;
}
static cl_object
create_thread()
{
cl_env_ptr the_env = ecl_core.first_env;
cl_object process, _env = ecl_cast_ptr(cl_object,the_env);
/* We have to set the environment before any allocation takes place,
* so that the interrupt handling code works. */
ecl_cs_init(the_env);
ecl_set_process_self(main_thread);
process = ecl_alloc_object(t_process);
process->process.phase = ECL_PROCESS_ACTIVE;
process->process.name = @'si::top-level';
process->process.function = ECL_NIL;
process->process.args = ECL_NIL;
process->process.thread = main_thread;
process->process.env = the_env;
process->process.woken_up = ECL_NIL;
ecl_mutex_init(&process->process.start_stop_lock, TRUE);
ecl_cond_var_init(&process->process.exit_barrier);
the_env->own_process = process;
{
cl_object v = si_make_vector(ECL_T, /* Element type */
ecl_make_fixnum(256), /* Size */
ecl_make_fixnum(0), /* fill pointer */
ECL_NIL, ECL_NIL, ECL_NIL);
v->vector.self.t[0] = process;
v->vector.fillp = 1;
cl_core.processes = v;
}
ecl_stack_push(ecl_core.threads, _env);
return ECL_NIL;
}
static cl_object
enable_thread()
{
return ECL_NIL;
}
static cl_object
init_env_thread(cl_env_ptr the_env)
{
return ECL_NIL;
}
static cl_object
init_cpu_thread(cl_env_ptr the_env)
{
return ECL_NIL;
}
static cl_object
free_cpu_thread(cl_env_ptr the_env)
{
return ECL_NIL;
}
static cl_object
free_env_thread(cl_env_ptr the_env)
{
return ECL_NIL;
}
ecl_def_ct_base_string(str_thread, "THREAD", 6, static, const);
static struct ecl_module module_thread = {
.name = str_thread,
.create = create_thread,
.enable = enable_thread,
.init_env = init_env_thread,
.init_cpu = init_cpu_thread,
.free_cpu = free_cpu_thread,
.free_env = free_env_thread,
.disable = ecl_module_no_op,
.destroy = ecl_module_no_op
};
cl_object ecl_module_thread = (cl_object)&module_thread;

View file

@ -221,18 +221,14 @@ cl_get_internal_real_time()
cl_object
cl_get_universal_time()
{
cl_env_ptr env = ecl_process_env();
cl_object utc = ecl_make_integer(time(0));
@(return ecl_plus(utc, cl_core.Jan1st1970UT));
ecl_return1(env, ecl_plus(utc, ecl_ct_Jan1st1970UT));
}
void
init_unixtime(void)
{
ecl_get_internal_real_time(&beginning);
ECL_SET(@'internal-time-units-per-second', ecl_make_fixnum(1000000));
cl_core.Jan1st1970UT =
ecl_times(ecl_make_fixnum(24 * 60 * 60),
ecl_make_fixnum(17 + 365 * 70));
}

View file

@ -181,6 +181,10 @@ ecl_type_to_symbol(cl_type t)
return @'si::foreign-data';
case t_frame:
return @'si::frame';
case t_exception:
return @'si::exception';
case t_module:
return @'si::module';
case t_weak_pointer:
return @'ext::weak-pointer';
#ifdef ECL_SSE2

View file

@ -1085,7 +1085,7 @@ dir_recursive(cl_object base_dir, cl_object directory, cl_object filemask, int f
cl_object
si_get_library_pathname(void)
{
cl_object s = cl_core.library_pathname;
cl_object s = ecl_core.library_pathname;
if (!Null(s)) {
goto OUTPUT_UNCHANGED;
} else {
@ -1100,11 +1100,11 @@ si_get_library_pathname(void)
ecl_filename_char *buffer;
HMODULE hnd;
cl_index len, ep;
s = ecl_alloc_adjustable_filename(cl_core.path_max);
s = ecl_alloc_adjustable_filename(ecl_core.path_max);
buffer = ecl_filename_self(s);
ecl_disable_interrupts();
hnd = GetModuleHandle("ecl.dll");
len = ecl_GetModuleFileName(hnd, buffer, cl_core.path_max-1);
len = ecl_GetModuleFileName(hnd, buffer, ecl_core.path_max-1);
ecl_enable_interrupts();
if (len == 0) {
FEerror("GetModuleFileName failed (last error = ~S)",
@ -1125,9 +1125,9 @@ si_get_library_pathname(void)
s = current_dir();
}
}
cl_core.library_pathname = ecl_decode_filename(s, ECL_NIL);
ecl_core.library_pathname = ecl_decode_filename(s, ECL_NIL);
OUTPUT_UNCHANGED:
@(return cl_core.library_pathname);
@(return ecl_core.library_pathname);
}
@(defun ext::chdir (directory &optional (change_d_p_d ECL_T))

View file

@ -41,7 +41,7 @@
* sections of code which are interruptible, and in which it is safe
* for the handler to run arbitrary code, protect anything else. In
* principle this "marking" can be done using POSIX functions such as
* pthread_sigmask() or sigprocmask().
* pthread_sigmask() or sigprocmask() abstracted with ecl_sigmask().
*
* However in practice this is slow, as it involves at least a
* function call, resolving thread-local variables, etc, etc, and it
@ -257,7 +257,7 @@ static ECL_INLINE bool
interrupts_disabled_by_lisp(cl_env_ptr the_env)
{
return !ecl_option_values[ECL_OPT_BOOTED] ||
Null(ECL_SYM_VAL(the_env, @'ext::*interrupts-enabled*'));
Null(ECL_SYM_VAL(the_env, ECL_INTERRUPTS_ENABLED));
}
static void early_signal_error() ecl_attr_noreturn;
@ -265,8 +265,8 @@ static void early_signal_error() ecl_attr_noreturn;
static void
early_signal_error()
{
ecl_internal_error("Got signal before environment was installed"
" on our thread");
ecl_internal_error
("Got signal before environment was installed on our thread");
}
static void illegal_signal_code(cl_object code) ecl_attr_noreturn;
@ -307,11 +307,7 @@ unblock_signal(cl_env_ptr the_env, int signal)
* We do not really "unblock" the signal, but rather restore
* ECL's default sigmask.
*/
# ifdef ECL_THREADS
pthread_sigmask(SIG_SETMASK, the_env->default_sigmask, NULL);
# else
sigprocmask(SIG_SETMASK, the_env->default_sigmask, NULL);
# endif
ecl_sigmask(SIG_SETMASK, the_env->default_sigmask, NULL);
}
#endif
@ -366,15 +362,14 @@ handle_all_queued(cl_env_ptr env)
static void
handle_all_queued_interrupt_safe(cl_env_ptr env)
{
/* We have to save and later restore thread-local variables to
* ensure that they don't get overwritten by the interrupting
* code */
/* INV: - IHS stack manipulations are interrupt safe
* - The rest of the thread local variables are
* guaranteed to be used in an interrupt safe way. This
* is not true for the compiler environment and ffi
* data, but it is unclear whether the DFFI or compiler
* are thread safe anyway. */
/* We have to save and later restore thread-local variables to ensure that
* they don't get overwritten by the interrupting code. */
/* FIXME introduce save/load procedure in modules. */
/* INV IHS stack manipulations are interrupt safe; the rest of the thread
* local variables are guaranteed to be used in an interrupt safe way[1].
*
* [1] This is not true for the compiler environment and ffi data, but it is
* unclear whether the DFFI or the compiler are thread safe anyway. */
cl_object fun = env->function;
cl_index nvalues = env->nvalues;
cl_object values[ECL_MULTIPLE_VALUES_LIMIT];
@ -387,7 +382,8 @@ handle_all_queued_interrupt_safe(cl_env_ptr env)
* not init and clear them before calling the interrupting
* code we would risk memory leaks. */
cl_object big_register[ECL_BIGNUM_REGISTER_NUMBER];
memcpy(big_register, env->big_register, ECL_BIGNUM_REGISTER_NUMBER*sizeof(cl_object));
cl_index big_register_size = ECL_BIGNUM_REGISTER_NUMBER*sizeof(cl_object);
ecl_copy(big_register, env->big_register, big_register_size);
ecl_init_bignum_registers(env);
/* We might have been interrupted while we push/pop in the stack. Increasing
* env->run_stack.top ensures that we don't overwrite the topmost stack
@ -407,8 +403,8 @@ handle_all_queued_interrupt_safe(cl_env_ptr env)
memcpy(env->bds_stack.top+1, &top_binding, sizeof(struct ecl_bds_frame));
memcpy(env->frs_stack.top+1, &top_frame, sizeof(struct ecl_frame));
env->run_stack.top--;
ecl_clear_bignum_registers(env);
memcpy(env->big_register, big_register, ECL_BIGNUM_REGISTER_NUMBER*sizeof(cl_object));
ecl_free_bignum_registers(env);
ecl_copy(env->big_register, big_register, big_register_size);
env->packages_to_be_created_p = packages_to_be_created_p;
env->packages_to_be_created = packages_to_be_created;
env->stack_frame = stack_frame;
@ -534,7 +530,7 @@ handler_fn_prototype(non_evil_signal_handler, int sig, siginfo_t *siginfo, void
unlikely_if (zombie_process(the_env))
return;
signal_object = ecl_gethash_safe(ecl_make_fixnum(sig),
cl_core.known_signals,
ecl_core.known_signals,
ECL_NIL);
handle_or_queue(the_env, signal_object, sig);
errno = old_errno;
@ -552,7 +548,7 @@ handler_fn_prototype(evil_signal_handler, int sig, siginfo_t *siginfo, void *dat
unlikely_if (zombie_process(the_env))
return;
signal_object = ecl_gethash_safe(ecl_make_fixnum(sig),
cl_core.known_signals,
ecl_core.known_signals,
ECL_NIL);
handle_signal_now(signal_object);
errno = old_errno;
@ -619,7 +615,7 @@ asynchronous_signal_servicing_thread()
sigdelset(&handled_set, SIGSEGV);
sigdelset(&handled_set, SIGBUS);
}
pthread_sigmask(SIG_BLOCK, &handled_set, NULL);
ecl_sigmask(SIG_BLOCK, &handled_set, NULL);
}
/*
* We create the object for communication. We need a lock to prevent other
@ -629,6 +625,7 @@ asynchronous_signal_servicing_thread()
pipe(signal_thread_pipe);
ecl_mutex_unlock(&signal_thread_lock);
signal_thread_msg.process = ECL_NIL;
ECL_UNWIND_PROTECT_BEGIN(the_env);
for (;;) {
cl_object signal_code;
signal_thread_msg.process = ECL_NIL;
@ -647,7 +644,7 @@ asynchronous_signal_servicing_thread()
break;
}
signal_code = ecl_gethash_safe(ecl_make_fixnum(signal_thread_msg.signo),
cl_core.known_signals,
ecl_core.known_signals,
ECL_NIL);
if (!Null(signal_code)) {
mp_process_run_function(3, @'si::handle-signal',
@ -655,12 +652,14 @@ asynchronous_signal_servicing_thread()
signal_code);
}
}
ECL_UNWIND_PROTECT_EXIT;
# if defined(ECL_USE_MPROTECT)
/* We might have protected our own environment */
mprotect(the_env, sizeof(*the_env), PROT_READ | PROT_WRITE);
# endif /* ECL_USE_MPROTECT */
close(signal_thread_pipe[0]);
close(signal_thread_pipe[1]);
ECL_UNWIND_PROTECT_END;
ecl_return0(the_env);
}
#endif /* ECL_THREADS && !ECL_MS_WINDOWS_HOST */
@ -869,7 +868,7 @@ cl_object
si_check_pending_interrupts(void)
{
const cl_env_ptr the_env = ecl_process_env();
handle_all_queued(ecl_process_env());
handle_all_queued(the_env);
ecl_return0(the_env);
}
@ -906,25 +905,25 @@ do_catch_signal(int code, cl_object action, cl_object process)
return ECL_T;
} else {
sigset_t handled_set;
pthread_sigmask(SIG_SETMASK, NULL, &handled_set);
ecl_sigmask(SIG_SETMASK, NULL, &handled_set);
if (action == @':mask') {
sigaddset(&handled_set, code);
} else {
sigdelset(&handled_set, code);
}
pthread_sigmask(SIG_SETMASK, &handled_set, NULL);
ecl_sigmask(SIG_SETMASK, &handled_set, NULL);
return ECL_T;
}
# else
{
sigset_t handled_set;
sigprocmask(SIG_SETMASK, NULL, &handled_set);
ecl_sigmask(SIG_SETMASK, NULL, &handled_set);
if (action == @':mask') {
sigaddset(&handled_set, code);
} else {
sigdelset(&handled_set, code);
}
sigprocmask(SIG_SETMASK, &handled_set, NULL);
ecl_sigmask(SIG_SETMASK, &handled_set, NULL);
return ECL_T;
}
# endif /* !ECL_THREADS */
@ -950,8 +949,7 @@ do_catch_signal(int code, cl_object action, cl_object process)
}
return ECL_T;
} else {
FEerror("Unknown 2nd argument to EXT:CATCH-SIGNAL: ~A", 1,
action);
FEerror("Unknown 2nd argument to EXT:CATCH-SIGNAL: ~A", 1, action);
}
}
@ -959,7 +957,7 @@ cl_object
si_get_signal_handler(cl_object code)
{
const cl_env_ptr the_env = ecl_process_env();
cl_object handler = ecl_gethash_safe(code, cl_core.known_signals, OBJNULL);
cl_object handler = ecl_gethash_safe(code, ecl_core.known_signals, OBJNULL);
unlikely_if (handler == OBJNULL) {
illegal_signal_code(code);
}
@ -970,11 +968,11 @@ cl_object
si_set_signal_handler(cl_object code, cl_object handler)
{
const cl_env_ptr the_env = ecl_process_env();
cl_object action = ecl_gethash_safe(code, cl_core.known_signals, OBJNULL);
cl_object action = ecl_gethash_safe(code, ecl_core.known_signals, OBJNULL);
unlikely_if (action == OBJNULL) {
illegal_signal_code(code);
}
ecl_sethash(code, cl_core.known_signals, handler);
ecl_sethash(code, ecl_core.known_signals, handler);
si_catch_signal(2, code, ECL_T);
ecl_return0(the_env);
}
@ -984,7 +982,7 @@ si_set_signal_handler(cl_object code, cl_object handler)
{
const cl_env_ptr the_env = ecl_process_env();
int code_int;
unlikely_if (ecl_gethash_safe(code, cl_core.known_signals, OBJNULL) == OBJNULL) {
unlikely_if (ecl_gethash_safe(code, ecl_core.known_signals, OBJNULL) == OBJNULL) {
illegal_signal_code(code);
}
code_int = ecl_fixnum(code);
@ -992,19 +990,16 @@ si_set_signal_handler(cl_object code, cl_object handler)
# ifdef SIGSEGV
unlikely_if ((code == ecl_make_fixnum(SIGSEGV)) &&
ecl_option_values[ECL_OPT_INCREMENTAL_GC])
FEerror("It is not allowed to change the behavior of SIGSEGV.",
0);
FEerror("It is not allowed to change the behavior of SIGSEGV.", 0);
# endif
# ifdef SIGBUS
unlikely_if (code_int == SIGBUS)
FEerror("It is not allowed to change the behavior of SIGBUS.",
0);
FEerror("It is not allowed to change the behavior of SIGBUS.", 0);
# endif
#endif
#if defined(ECL_THREADS) && !defined(ECL_MS_WINDOWS_HOST)
unlikely_if (code_int == ecl_option_values[ECL_OPT_THREAD_INTERRUPT_SIGNAL]) {
FEerror("It is not allowed to change the behavior of signal ~D", 1,
code);
FEerror("It is not allowed to change the behavior of signal ~D", 1, code);
}
#endif
#ifdef SIGFPE
@ -1036,40 +1031,34 @@ wakeup_noop(ULONG_PTR foo)
static bool
do_interrupt_thread(cl_object process)
{
cl_env_ptr process_env = process->process.env;
# ifdef ECL_WINDOWS_THREADS
# ifndef ECL_USE_GUARD_PAGE
# error "Cannot implement ecl_interrupt_process without guard pages"
# endif
HANDLE thread = process->process.thread;
HANDLE thread = process_env->thread;
CONTEXT context;
void *trap_address = process->process.env;
void *trap_address = ecl_cast_ptr(void*, process_env);;
DWORD guard = PAGE_GUARD | PAGE_READWRITE;
int ok = 1;
if (SuspendThread(thread) == (DWORD)-1) {
FEwin32_error("Unable to suspend thread ~A", 1,
process);
FEwin32_error("Unable to suspend thread ~A", 1, process);
ok = 0;
goto EXIT;
}
process->process.interrupt = ECL_T;
if (!VirtualProtect(process->process.env,
sizeof(struct cl_env_struct),
guard,
&guard))
process_env->interrupt_struct->inside_interrupt = true;
if (!VirtualProtect(process_env, sizeof(struct cl_env_struct), guard, &guard))
{
FEwin32_error("Unable to protect memory from thread ~A",
1, process);
FEwin32_error("Unable to protect memory from thread ~A", 1, process);
ok = 0;
}
RESUME:
if (!QueueUserAPC(wakeup_function, thread, 0)) {
FEwin32_error("Unable to queue APC call to thread ~A",
1, process);
FEwin32_error("Unable to queue APC call to thread ~A", 1, process);
ok = 0;
}
if (ResumeThread(thread) == (DWORD)-1) {
FEwin32_error("Unable to resume thread ~A", 1,
process);
FEwin32_error("Unable to resume thread ~A", 1, process);
ok = 0;
goto EXIT;
}
@ -1077,9 +1066,8 @@ do_interrupt_thread(cl_object process)
return ok;
# else
int signal = ecl_option_values[ECL_OPT_THREAD_INTERRUPT_SIGNAL];
if (pthread_kill(process->process.thread, signal)) {
FElibc_error("Unable to interrupt process ~A", 1,
process);
if (pthread_kill(process_env->thread, signal)) {
FElibc_error("Unable to interrupt process ~A", 1, process);
}
return 1;
# endif
@ -1120,10 +1108,10 @@ void
ecl_wakeup_process(cl_object process)
{
# ifdef ECL_WINDOWS_THREADS
HANDLE thread = process->process.thread;
cl_env_ptr process_env = process->process.env;
HANDLE thread = process_env->thread;
if (!QueueUserAPC(wakeup_noop, thread, 0)) {
FEwin32_error("Unable to queue APC call to thread ~A",
1, process);
FEwin32_error("Unable to queue APC call to thread ~A", 1, process);
}
# else
do_interrupt_thread(process);
@ -1145,9 +1133,8 @@ _ecl_w32_exception_filter(struct _EXCEPTION_POINTERS* ep)
{
/* Access to guard page */
case STATUS_GUARD_PAGE_VIOLATION: {
cl_object process = the_env->own_process;
if (!Null(process->process.interrupt)) {
process->process.interrupt = ECL_NIL;
if(the_env->interrupt_struct->inside_interrupt) {
the_env->interrupt_struct->inside_interrupt = false;
handle_all_queued_interrupt_safe(the_env);
}
return EXCEPTION_CONTINUE_EXECUTION;
@ -1207,8 +1194,7 @@ static cl_object
W32_handle_in_new_thread(cl_object signal_code)
{
int outside_ecl = ecl_import_current_thread(@'si::handle-signal', ECL_NIL);
mp_process_run_function(3, @'si::handle-signal',
@'si::handle-signal',
mp_process_run_function(3, @'si::handle-signal', @'si::handle-signal',
signal_code);
if (outside_ecl) ecl_release_current_thread();
}
@ -1294,46 +1280,38 @@ si_trap_fpe(cl_object condition, cl_object flag)
* detect and process them.
*/
static void
install_asynchronous_signal_handlers()
install_asynchronous_signal_handlers(void)
{
#if defined(ECL_MS_WINDOWS_HOST)
# define async_handler(signal,handler,mask)
# define async_handler(signal,handler)
#else
# if defined(ECL_THREADS) && defined(HAVE_SIGPROCMASK)
# define async_handler(signal,handler,mask) { \
# define async_handler(signal,handler) { \
if (ecl_option_values[ECL_OPT_SIGNAL_HANDLING_THREAD]) { \
mysignal(signal, deferred_signal_handler); \
} else { \
mysignal(signal,handler); \
}}
# else
# define async_handler(signal,handler,mask) \
# define async_handler(signal,handler) \
mysignal(signal,handler)
# endif
#endif
#ifdef HAVE_SIGPROCMASK
sigset_t *sigmask = cl_core.default_sigmask = &main_thread_sigmask;
cl_core.default_sigmask_bytes = sizeof(sigset_t);
# ifdef ECL_THREADS
pthread_sigmask(SIG_SETMASK, NULL, sigmask);
# else
sigprocmask(SIG_SETMASK, NULL, sigmask);
# endif
sigset_t *sigmask = ecl_core.first_env->default_sigmask = &main_thread_sigmask;
ecl_core.default_sigmask_bytes = sizeof(sigset_t);
ecl_sigmask(SIG_SETMASK, NULL, sigmask);
#endif
#if defined(ECL_THREADS) && defined(HAVE_SIGPROCMASK)
ecl_mutex_init(&signal_thread_lock, TRUE);
#endif
#ifdef SIGINT
if (ecl_option_values[ECL_OPT_TRAP_SIGINT]) {
async_handler(SIGINT, non_evil_signal_handler, sigmask);
async_handler(SIGINT, non_evil_signal_handler);
}
#endif
#ifdef HAVE_SIGPROCMASK
# if defined(ECL_THREADS)
pthread_sigmask(SIG_SETMASK, sigmask, NULL);
# else
sigprocmask(SIG_SETMASK, sigmask, NULL);
# endif
ecl_sigmask(SIG_SETMASK, sigmask, NULL);
#endif
#ifdef ECL_WINDOWS_THREADS
old_W32_exception_filter =
@ -1345,42 +1323,76 @@ install_asynchronous_signal_handlers()
#undef async_handler
}
static void
uninstall_asynchronous_signal_handlers(void)
{
#ifdef HAVE_SIGPROCMASK
sigset_t *sigmask = ecl_core.first_env->default_sigmask = &main_thread_sigmask;
ecl_core.default_sigmask_bytes = sizeof(sigset_t);
ecl_sigmask(SIG_SETMASK, NULL, sigmask);
#endif
#if defined(ECL_THREADS) && defined(HAVE_SIGPROCMASK)
ecl_mutex_init(&signal_thread_lock, TRUE);
#endif
#ifdef SIGINT
if (ecl_option_values[ECL_OPT_TRAP_SIGINT]) {
mysignal(SIGINT, SIG_IGN);
}
#endif
#ifdef HAVE_SIGPROCMASK
ecl_sigmask(SIG_SETMASK, sigmask, NULL);
#endif
#ifdef ECL_WINDOWS_THREADS
SetUnhandledExceptionFilter(NULL);
if (ecl_option_values[ECL_OPT_TRAP_SIGINT]) {
SetConsoleCtrlHandler(W32_console_ctrl_handler, FALSE);
}
#endif
#undef async_handler
}
/*
* In POSIX systems we may set up a background thread that detects
* synchronous signals and spawns a new thread to handle each of them.
*/
static void
install_signal_handling_thread()
install_signal_handling_thread(void)
{
#if defined(ECL_THREADS) && defined(HAVE_SIGPROCMASK)
ecl_process_env()->default_sigmask = &main_thread_sigmask;
if (ecl_option_values[ECL_OPT_SIGNAL_HANDLING_THREAD]) {
cl_object fun =
ecl_make_cfun((cl_objectfn_fixed)
asynchronous_signal_servicing_thread,
@'si::signal-servicing',
ECL_NIL,
0);
ecl_make_cfun((cl_objectfn_fixed) asynchronous_signal_servicing_thread,
@'si::signal-servicing', ECL_NIL, 0);
cl_object process =
signal_thread_process =
mp_process_run_function_wait(2,
@'si::signal-servicing',
fun);
mp_process_run_function_wait(2, @'si::signal-servicing', fun);
if (Null(process)) {
ecl_internal_error("Unable to create signal "
"servicing thread");
ecl_internal_error("Unable to create signal servicing thread.");
}
}
#endif
}
static void
uninstall_signal_handling_thread(void)
{
#if defined(ECL_THREADS) && defined(HAVE_SIGPROCMASK)
if (ecl_option_values[ECL_OPT_SIGNAL_HANDLING_THREAD]
&& signal_thread_process->process.phase == ECL_PROCESS_ACTIVE) {
mp_process_kill(signal_thread_process);
mp_process_join(signal_thread_process);
}
#endif
}
/*
* This routine sets up handlers for all exceptions, such as access to
* restricted regions of memory. They have to be set up before we call
* init_GC().
*/
static void
install_synchronous_signal_handlers()
install_synchronous_signal_handlers(void)
{
#ifdef SIGBUS
if (ecl_option_values[ECL_OPT_TRAP_SIGBUS]) {
@ -1416,13 +1428,55 @@ install_synchronous_signal_handlers()
int signal = ecl_option_values[ECL_OPT_THREAD_INTERRUPT_SIGNAL];
if (signal == 0) {
signal = DEFAULT_THREAD_INTERRUPT_SIGNAL;
ecl_set_option(ECL_OPT_THREAD_INTERRUPT_SIGNAL,
signal);
ecl_set_option(ECL_OPT_THREAD_INTERRUPT_SIGNAL, signal);
}
mysignal(signal, process_interrupt_handler);
#ifdef HAVE_SIGPROCMASK
sigdelset(&main_thread_sigmask, signal);
pthread_sigmask(SIG_SETMASK, &main_thread_sigmask, NULL);
ecl_sigmask(SIG_SETMASK, &main_thread_sigmask, NULL);
#endif
}
#endif
}
static void
uninstall_synchronous_signal_handlers(void)
{
#ifdef SIGBUS
if (ecl_option_values[ECL_OPT_TRAP_SIGBUS]) {
do_catch_signal(SIGBUS, ECL_NIL, ECL_NIL);
}
#endif
#ifdef SIGSEGV
if (ecl_option_values[ECL_OPT_TRAP_SIGSEGV]) {
do_catch_signal(SIGSEGV, ECL_NIL, ECL_NIL);
}
#endif
#ifdef SIGPIPE
if (ecl_option_values[ECL_OPT_TRAP_SIGPIPE]) {
do_catch_signal(SIGPIPE, ECL_NIL, ECL_NIL);
}
#endif
#ifdef SIGILL
if (ecl_option_values[ECL_OPT_TRAP_SIGILL]) {
do_catch_signal(SIGILL, ECL_NIL, ECL_NIL);
}
#endif
/* In order to implement MP:INTERRUPT-PROCESS, MP:PROCESS-KILL
* and the like, we use signals. This sets up a synchronous
* signal handler for that particular signal.
*/
#if defined(ECL_THREADS) && !defined(ECL_MS_WINDOWS_HOST)
if (ecl_option_values[ECL_OPT_TRAP_INTERRUPT_SIGNAL]) {
int signal = ecl_option_values[ECL_OPT_THREAD_INTERRUPT_SIGNAL];
if (signal == 0) {
signal = DEFAULT_THREAD_INTERRUPT_SIGNAL;
ecl_set_option(ECL_OPT_THREAD_INTERRUPT_SIGNAL, signal);
}
mysignal(signal, SIG_IGN);
#ifdef HAVE_SIGPROCMASK
sigdelset(&main_thread_sigmask, signal);
ecl_sigmask(SIG_SETMASK, &main_thread_sigmask, NULL);
#endif
}
#endif
@ -1472,15 +1526,14 @@ static void
create_signal_code_constants()
{
cl_object hash =
cl_core.known_signals =
ecl_core.known_signals =
cl__make_hash_table(@'eql', ecl_make_fixnum(128),
cl_core.rehash_size,
cl_core.rehash_threshold);
ecl_ct_default_rehash_size,
ecl_ct_default_rehash_threshold);
int i;
for (i = 0; known_signals[i].code >= 0; i++) {
add_one_signal(hash, known_signals[i].code,
_ecl_intern(known_signals[i].name,
cl_core.ext_package),
_ecl_intern(known_signals[i].name, cl_core.ext_package),
known_signals[i].handler);
}
#ifdef SIGRTMIN
@ -1503,17 +1556,130 @@ create_signal_code_constants()
#endif
}
void
init_unixint(int pass)
/* -- module definition ------------------------------------------------------ */
static cl_object
create_unixint(void)
{
if (pass == 0) {
install_asynchronous_signal_handlers();
install_synchronous_signal_handlers();
} else {
create_signal_code_constants();
install_fpe_signal_handlers();
install_signal_handling_thread();
ECL_SET(@'ext::*interrupts-enabled*', ECL_T);
ecl_process_env()->disable_interrupts = 0;
}
cl_env_ptr the_env = ecl_core.first_env;
the_env->default_sigmask = NULL;
the_env->interrupt_struct = NULL;
ecl_disable_interrupts_env(the_env);
/* Install handlers */
install_asynchronous_signal_handlers();
install_synchronous_signal_handlers();
return ECL_NIL;
}
static cl_object
enable_unixint(void)
{
create_signal_code_constants();
install_fpe_signal_handlers();
install_signal_handling_thread();
ECL_SET(ECL_INTERRUPTS_ENABLED, ECL_T);
ecl_process_env()->disable_interrupts = 0;
return ECL_NIL;
}
static cl_object
init_env_unixint(cl_env_ptr the_env)
{
cl_env_ptr parent_env = ecl_process_env_unsafe();
size_t bytes = ecl_core.default_sigmask_bytes;
if (bytes == 0) {
the_env->default_sigmask = 0;
} else if (parent_env) {
the_env->default_sigmask = ecl_alloc_atomic(bytes);
memcpy(the_env->default_sigmask, parent_env->default_sigmask, bytes);
} else {
the_env->default_sigmask = ecl_core.first_env->default_sigmask;
}
the_env->interrupt_struct = ecl_alloc(sizeof(*the_env->interrupt_struct));
the_env->interrupt_struct->pending_interrupt = ECL_NIL;
#ifdef ECL_THREADS
ecl_mutex_init(&the_env->interrupt_struct->signal_queue_lock, FALSE);
#endif
#ifdef ECL_WINDOWS_THREADS
the_env->interrupt_struct->inside_interrupt = false;
#endif
{
int size = ecl_option_values[ECL_OPT_SIGNAL_QUEUE_SIZE];
the_env->interrupt_struct->signal_queue = cl_make_list(1, ecl_make_fixnum(size));
}
the_env->fault_address = the_env;
the_env->trap_fpe_bits = 0;
/* An fresh environment _always_ disables interrupts. They are activated later
* on by the thread entry point or ecl_module_unixint. */
ecl_disable_interrupts_env(the_env);
return ECL_NIL;
}
static cl_object
init_cpu_unixint(cl_env_ptr the_env)
{
return ECL_NIL;
}
static cl_object
free_cpu_unixint(cl_env_ptr the_env)
{
ecl_disable_interrupts_env(the_env);
return ECL_NIL;
}
static cl_object
free_env_unixint(cl_env_ptr the_env)
{
#ifdef ECL_THREADS
ecl_mutex_destroy(&the_env->interrupt_struct->signal_queue_lock);
#endif
the_env->trap_fpe_bits = 0;
si_trap_fpe(@'last', ECL_NIL);
return ECL_NIL;
}
static cl_object
disable_unixint(void)
{
cl_env_ptr the_env = ecl_core.first_env;
ecl_disable_interrupts_env(the_env);
ECL_SET(ECL_INTERRUPTS_ENABLED, ECL_NIL);
return ECL_NIL;
}
static cl_object
destroy_unixint(void)
{
uninstall_signal_handling_thread();
uninstall_synchronous_signal_handlers();
uninstall_asynchronous_signal_handlers();
/* FIXME this is messy. */
/* remove_signal_code_constants(); */
return ECL_NIL;
}
/* KLUDGE UNIXINT and MEM_GC are interwened - GC expects stop_world to work and
unixint relies on the GC to allocate its internal structures.
When we start add MEM_GC module before UNIXINT and enable GC after both are
created. That is enough to get GC going. Finally we enable UNIXINT.
When we adopt a new cpu we first disable MEM_GC, then initialize UNIXINT
(allocator works fine despite GC collector being disabled), then initialize
GC to register the current thread and enable the GC. -- jd 2024-12-05 */
ecl_def_ct_base_string(str_unixint, "UNIXINT", 7, static, const);
static struct ecl_module module_unixint = {
.name = str_unixint,
.create = create_unixint,
.enable = enable_unixint,
.init_env = init_env_unixint,
.init_cpu = init_cpu_unixint,
.free_cpu = free_cpu_unixint,
.free_env = free_env_unixint,
.disable = disable_unixint,
.destroy = destroy_unixint
};
cl_object ecl_module_unixint = (cl_object)&module_unixint;

View file

@ -88,15 +88,6 @@
:function f)))
*restart-clusters*)))
(defun bind-simple-handlers (tag names)
(flet ((simple-handler-function (tag code)
#'(lambda (c) (throw tag (values code c)))))
(cons (loop for i from 1
for n in (if (atom names) (list names) names)
for f = (simple-handler-function tag i)
collect (cons n f))
*handler-clusters*)))
(defmacro restart-bind (bindings &body forms)
`(let ((*restart-clusters*
(cons (list ,@(mapcar #'(lambda (binding)
@ -382,28 +373,33 @@
|#
(defparameter *handler-clusters* nil)
(defvar *signal-handlers* nil)
(defmacro handler-bind (bindings &body forms)
(unless (every #'(lambda (x) (and (listp x) (= (length x) 2))) bindings)
(error "Ill-formed handler bindings."))
`(let ((*handler-clusters*
(cons (list ,@(mapcar #'(lambda (x) `(cons ',(car x) ,(cadr x)))
bindings))
*handler-clusters*)))
,@forms))
(defmacro handler-bind (bindings &body body)
(with-gensyms (handler condition)
`(flet ((,handler (,condition)
(typecase ,condition
,@(loop for (type func . rest) in bindings
when rest do
(error "Ill-formed handler bindings.")
collect `(,type (funcall ,func ,condition))))))
(declare (dynamic-extent (function ,handler)))
(let ((*signal-handlers* (cons (function ,handler) *signal-handlers*)))
,@body))))
(defun bind-simple-handlers (tag names)
(flet ((simple-handler (condition)
(loop for code from 1
for type in (if (atom names) (list names) names)
when (typep condition type) do
(throw tag (values code condition)))))
(cons #'simple-handler *signal-handlers*)))
(defun signal (datum &rest arguments)
(let* ((condition
(coerce-to-condition datum arguments 'SIMPLE-CONDITION 'SIGNAL))
(*handler-clusters* *handler-clusters*))
(let ((condition (coerce-to-condition datum arguments 'SIMPLE-CONDITION 'SIGNAL)))
(when (typep condition *break-on-signals*)
(break "~A~%Break entered because of *BREAK-ON-SIGNALS*." condition))
(loop (unless *handler-clusters* (return))
(let ((cluster (pop *handler-clusters*)))
(dolist (handler cluster)
(when (typep condition (car handler))
(funcall (cdr handler) condition)))))
(%signal condition t nil)
nil))

View file

@ -228,6 +228,8 @@
(si::code-block)
(si::foreign-data)
(si::frame)
(si::exception)
(si::module)
(si::weak-pointer)
(:threads mp::process)
(:threads mp::lock)

View file

@ -42,12 +42,12 @@
'(
;; Order is important: on platforms where 0.0 and -0.0 are the same
;; the last one is prioritized.
(#.(coerce 0 'cl:single-float) "cl_core.singlefloat_zero")
(#.(coerce 0 'cl:double-float) "cl_core.doublefloat_zero")
(#.(coerce -0.0 'cl:single-float) "cl_core.singlefloat_minus_zero")
(#.(coerce -0.0 'cl:double-float) "cl_core.doublefloat_minus_zero")
(#.(coerce 0 'cl:long-float) "cl_core.longfloat_zero")
(#.(coerce -0.0 'cl:long-float) "cl_core.longfloat_minus_zero")
(#.(coerce 0 'cl:single-float) "ecl_ct_singlefloat_zero")
(#.(coerce 0 'cl:double-float) "ecl_ct_doublefloat_zero")
(#.(coerce -0.0 'cl:single-float) "ecl_ct_singlefloat_minus_zero")
(#.(coerce -0.0 'cl:double-float) "ecl_ct_doublefloat_minus_zero")
(#.(coerce 0 'cl:long-float) "ecl_ct_longfloat_zero")
(#.(coerce -0.0 'cl:long-float) "ecl_ct_longfloat_minus_zero")
;; We temporarily remove this constant, because the bytecodes compiler
;; does not know how to externalize it.

View file

@ -199,7 +199,7 @@
(wt-nl "ecl_bds_unwind_n(cl_env_copy," bds-bind ");"))
(case ihs-p
(IHS (wt-nl "ecl_ihs_pop(cl_env_copy);"))
(IHS-ENV (wt-nl "ihs.lex_env = _ecl_debug_env;"))))
(IHS-ENV (wt-nl "ihs.lcl_env = _ecl_debug_env;"))))
(defun %unwind (into from)
(declare (si::c-local))

View file

@ -207,7 +207,7 @@
(push 'IHS *unwind-exit*)
(when (policy-debug-variable-bindings)
(build-debug-lexical-env (reverse requireds) t))
(wt-nl "ecl_ihs_push(cl_env_copy,&ihs," fname ",_ecl_debug_env);")))
(wt-nl "ecl_ihs_push(cl_env_copy,&ihs," fname ",ECL_NIL,_ecl_debug_env);")))
;; Bind optional parameters as long as there remain arguments.
(when optionals

View file

@ -75,11 +75,11 @@
(+ 2 (length filtered-locations))
",,);")
(unless first
(wt-nl "ihs.lex_env = _ecl_debug_env;")))
(wt-nl "ihs.lcl_env = _ecl_debug_env;")))
filtered-codes))
(defun pop-debug-lexical-env ()
(wt-nl "ihs.lex_env = _ecl_debug_env;"))
(wt-nl "ihs.lcl_env = _ecl_debug_env;"))
(defun c2let* (c1form vars forms body
&aux

View file

@ -298,7 +298,9 @@
(proclamation si:ihs-top () si::index)
(proclamation si:ihs-fun (si::index) (or null function-designator))
(proclamation si:ihs-env (si::index) environment)
(proclamation si:ihs-env (si::index) (or null vector))
(proclamation si:ihs-lex (si::index) (or null vector))
(proclamation si:ihs-lcl (si::index) (or null vector si::frame))
(proclamation si:frs-top () si::index)
(proclamation si:frs-bds (si::index) si::index)
(proclamation si:frs-tag (si::index) t)

33
src/configure vendored
View file

@ -6100,9 +6100,10 @@ SHAREDPREFIX='lib'
LIBPREFIX='lib'
LIBEXT='a'
PICFLAG='-fPIC'
THREAD_CFLAGS=''
THREAD_CFLAGS='-DGC_NO_THREAD_REDIRECTS'
THREAD_LIBS=''
THREAD_GC_FLAGS='--enable-threads=posix'
CFLAGS=''
INSTALL_TARGET='install'
THREAD_OBJ="$THREAD_OBJ threads/thread threads/mutex threads/condition_variable threads/semaphore threads/barrier threads/mailbox threads/rwlock"
clibs='-lm'
@ -6111,7 +6112,7 @@ SONAME_LDFLAGS=''
case "${host_os}" in
linux-android*)
thehost='ANDROID'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
ECL_LDRPATH='-Wl,--rpath,~A'
@ -6130,7 +6131,7 @@ LSP_FEATURES="${LSP_FEATURES} :unix"
# libdir may have a dollar expression inside
linux*)
thehost='linux'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_LIBS='-lpthread'
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
@ -6146,7 +6147,7 @@ LSP_FEATURES="${LSP_FEATURES} :unix"
;;
gnu*)
thehost='gnu'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_LIBS='-lpthread'
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
@ -6161,7 +6162,7 @@ LSP_FEATURES="${LSP_FEATURES} :unix"
;;
kfreebsd*-gnu)
thehost='kfreebsd'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_LIBS='-lpthread'
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
@ -6227,8 +6228,6 @@ LSP_FEATURES="${LSP_FEATURES} :bsd"
;;
openbsd*)
thehost='openbsd'
THREAD_CFLAGS=''
THREAD_LIBS=''
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
ECL_LDRPATH="-Wl,--rpath,~A"
@ -6265,7 +6264,7 @@ LSP_FEATURES="${LSP_FEATURES} :unix"
thehost='cygwin'
#enable_threads='no'
shared='yes'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_LIBS='-lpthread'
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
@ -6290,7 +6289,7 @@ LSP_FEATURES="${LSP_FEATURES} :unix"
clibs=''
shared='yes'
enable_threads='yes'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_GC_FLAGS='--enable-threads=win32'
SHARED_LDFLAGS="-Wl,--stack,${ECL_DEFAULT_C_STACK_SIZE}"
BUNDLE_LDFLAGS="-Wl,--stack,${ECL_DEFAULT_C_STACK_SIZE}"
@ -6432,7 +6431,7 @@ fi
SHARED_LDFLAGS="-dynamiclib ${LDFLAGS}"
BUNDLE_LDFLAGS="-bundle ${LDFLAGS}"
ECL_LDRPATH='-Wl,-rpath,~A'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_LIBS='-lpthread'
# The GMP library has not yet been ported to Intel or Arm-OSX
case "`uname -m`" in
@ -6476,7 +6475,7 @@ LSP_FEATURES="${LSP_FEATURES} :unix"
thehost='nonstop'
shared='yes'
PICFLAG='-call_shared'
THREAD_CFLAGS='-spthread'
THREAD_CFLAGS="-spthread ${THREAD_CFLAGS}"
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
ECL_LDRPATH='-Wld=\"-rld_l ~A\"'
@ -6484,7 +6483,6 @@ LSP_FEATURES="${LSP_FEATURES} :unix"
;;
haiku*)
thehost='haiku'
THREAD_LIBS=''
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
ECL_LDRPATH="-Wl,--rpath,~A"
@ -6517,7 +6515,7 @@ esac
case "${host}" in
*-nacl)
thehost='linux'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_LIBS='-lpthread'
SHARED_LDFLAGS="-shared ${LDFLAGS}"
BUNDLE_LDFLAGS="-shared ${LDFLAGS}"
@ -6531,7 +6529,7 @@ LSP_FEATURES="${LSP_FEATURES} :nacl"
;;
*-pnacl)
thehost='linux'
THREAD_CFLAGS='-D_THREAD_SAFE'
THREAD_CFLAGS="-D_THREAD_SAFE ${THREAD_CFLAGS}"
THREAD_LIBS='-lpthread'
CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 ${CFLAGS}"
@ -7216,7 +7214,7 @@ if test "${enable_threads}" = "yes" ; then
as_fn_error $? "Threads aren't supported on this system." "$LINENO" 5
else
LIBS="${THREAD_LIBS} ${LIBS}"
CFLAGS="${CFLAGS} ${THREAD_CFLAGS}"
CFLAGS="${CFLAGS} ${THREAD_CFLAGS} -DGC_NO_THREAD_REDIRECTS"
ac_fn_c_check_func "$LINENO" "pthread_rwlock_init" "ac_cv_func_pthread_rwlock_init"
if test "x$ac_cv_func_pthread_rwlock_init" = xyes
@ -7274,8 +7272,6 @@ fi
if test ${enable_boehm} = "no" ; then
as_fn_error $? "Boehm GC library is currently needed to build ECL" "$LINENO" 5;
EXTRA_OBJS="${EXTRA_OBJS} alloc.${OBJEXT} gbc.${OBJEXT}"
enable_smallcons="no"
else
@ -7528,7 +7524,6 @@ printf "%s\n" "${system_boehm} " >&6; }
fi
else
FASL_LIBS="${FASL_LIBS} -lgc"
EXTRA_OBJS="${EXTRA_OBJS} alloc_2.${OBJEXT}"
printf "%s\n" "#define GBC_BOEHM 1" >>confdefs.h
@ -7558,7 +7553,6 @@ printf "%s\n" "$as_me: Configuring included Boehm GC library:" >&6;}
ECL_BOEHM_GC_HEADER='ecl/gc/gc.h'
SUBDIRS="${SUBDIRS} gc"
CORE_LIBS="-leclgc ${CORE_LIBS}"
EXTRA_OBJS="${EXTRA_OBJS} alloc_2.${OBJEXT}"
if test "${enable_shared}" = "no"; then
LIBRARIES="${LIBRARIES} ${LIBPREFIX}eclgc.${LIBEXT}"
fi
@ -7715,7 +7709,6 @@ printf "%s\n" "$as_me: Configuring included libffi library:" >&6;}
ECL_LIBFFI_HEADER='ecl/ffi.h'
SUBDIRS="${SUBDIRS} libffi"
CORE_LIBS="-leclffi ${CORE_LIBS}"
EXTRA_OBJS="${EXTRA_OBJS} alloc_2.${OBJEXT}"
if test "${enable_shared}" = "no"; then
LIBRARIES="${LIBRARIES} ${LIBPREFIX}eclffi.${LIBEXT}"
fi

View file

@ -603,8 +603,6 @@ dnl ----------------------------------------------------------------------
dnl Boehm-Weiser garbage collector
if test ${enable_boehm} = "no" ; then
AC_MSG_ERROR([Boehm GC library is currently needed to build ECL]);
EXTRA_OBJS="${EXTRA_OBJS} alloc.${OBJEXT} gbc.${OBJEXT}"
enable_smallcons="no"
else
ECL_BOEHM_GC
ECL_ADD_FEATURE(boehm-gc)

View file

@ -13,6 +13,7 @@
enum {
OP_NOP,
OP_QUOTE,
OP_CALLW,
OP_ENDP,
OP_CONS,
OP_CAR,
@ -176,6 +177,7 @@ typedef int16_t cl_opcode;
static const int offsets[] = {\
&&LBL_OP_NOP - &&LBL_OP_NOP,\
&&LBL_OP_QUOTE - &&LBL_OP_NOP,\
&&LBL_OP_CALLW - &&LBL_OP_NOP,\
&&LBL_OP_ENDP - &&LBL_OP_NOP,\
&&LBL_OP_CONS - &&LBL_OP_NOP,\
&&LBL_OP_CAR - &&LBL_OP_NOP,\

View file

@ -129,35 +129,91 @@
#define ecl_cast_ptr(type,n) ((type)(n))
#endif
#define ecl_constexpr_string(name) \
((struct ecl_base_string) \
{ (int8_t)t_base_string, 0, ecl_aet_bc, 0, ECL_NIL, \
(cl_index)((sizeof(name)-1)), (cl_index)((sizeof(name)-1)), \
(ecl_base_char*)(name) })
#ifdef ECL_THREADS
#define ecl_constexpr_symbol(type, name, value) \
((struct ecl_symbol) \
{ (int8_t)t_symbol, 0, type, 0, \
value, ECL_NIL /*gfdef*/, NULL /*undefined_function_entry*/, \
ECL_NIL, ECL_NIL, ECL_NIL, (cl_object)&ecl_constexpr_string(name), \
ECL_NIL, ECL_NIL, ECL_MISSING_SPECIAL_BINDING } )
#else
#define ecl_constexpr_symbol(type, name, value) \
((struct ecl_symbol) \
{ (int8_t)t_symbol, 0, type, 0, \
value, ECL_NIL /*gfdef*/, NULL /*undefined_function_entry*/, \
ECL_NIL, ECL_NIL, ECL_NIL, (cl_object)&ecl_constexpr_string(name), \
ECL_NIL, ECL_NIL } )
#endif
#define ecl_def_variable(name, value, chars, len) \
ecl_def_ct_base_string (name ## _var_name, chars, len,static,const); \
ecl_def_ct_token(name, ecl_stp_special, name ## _var_name, value,,)
#define ecl_def_constant(name, value, chars, len) \
ecl_def_ct_base_string (name ## _var_name, chars, len,static,const); \
ecl_def_ct_token(name, ecl_stp_constant, name ## _var_name, value,,const)
#ifdef ECL_THREADS
#define ecl_def_ct_token(name,stype,sname,value,static,const) \
static const struct ecl_symbol name ## _data = { \
(int8_t)t_symbol, 0, stype, 0, \
value, ECL_NIL, NULL /*ecl_undefined_function_entry*/, \
ECL_NIL, ECL_NIL, ECL_NIL, sname, ECL_NIL, ECL_NIL, \
ECL_MISSING_SPECIAL_BINDING }; \
static const cl_object name = (cl_object)(& name ## _data)
#else
#define ecl_def_ct_token(name,stype,sname,value,static,const) \
static const struct ecl_symbol name ## _data = { \
(int8_t)t_symbol, 0, stype, 0, \
value, ECL_NIL, NULL /*ecl_undefined_function_entry*/, \
ECL_NIL, ECL_NIL, ECL_NIL, sname, ECL_NIL, ECL_NIL }; \
static const cl_object name = (cl_object)(& name ## _data)
#endif
#define ecl_def_function(name, cname, static, const) \
static const struct ecl_cfunfixed name ##_data = { \
(int8_t)t_cfunfixed, 0, 0, 0, \
/*name*/ECL_NIL, /*block*/ECL_NIL, \
/*entry*/(cl_objectfn)cname, \
/*funfixed_entry*/(cl_objectfn_fixed)NULL, \
ECL_NIL, ECL_NIL }; \
static const cl_object name = (cl_object)(& name ## _data)
#define ecl_def_string_array(name,static,const) \
static const union { \
struct ecl_base_string elt; \
cl_fixnum padding[(sizeof(struct ecl_base_string)+3)/4*4]; \
} name[]
#define ecl_def_string_array_elt(chars) { { \
(int8_t)t_base_string, 0, ecl_aet_bc, 0, \
ECL_NIL, (cl_index)(sizeof(chars))-1, \
(cl_index)(sizeof(chars))-1, \
#define ecl_def_string_array_elt(chars) { { \
(int8_t)t_base_string, 0, ecl_aet_bc, 0, \
ECL_NIL, (cl_index)(sizeof(chars))-1, \
(cl_index)(sizeof(chars))-1, \
(ecl_base_char*)(chars) } }
#define ecl_def_ct_base_string(name,chars,len,static,const) \
static const struct ecl_base_string name ## _data = { \
#define ecl_def_ct_base_string(name,chars,len,static,const) \
static const struct ecl_base_string name ## _data = { \
(int8_t)t_base_string, 0, ecl_aet_bc, 0, \
ECL_NIL, (cl_index)(len), (cl_index)(len), \
(ecl_base_char*)(chars) }; \
ECL_NIL, (cl_index)(len), (cl_index)(len), \
(ecl_base_char*)(chars) }; \
static const cl_object name = (cl_object)(& name ## _data)
#define ecl_def_ct_single_float(name,f,static,const) \
static const struct ecl_singlefloat name ## _data = { \
(int8_t)t_singlefloat, 0, 0, 0, \
(float)(f) }; \
#define ecl_def_ct_single_float(name,f,static,const) \
static const struct ecl_singlefloat name ## _data = { \
(int8_t)t_singlefloat, 0, 0, 0, \
(float)(f) }; \
static const cl_object name = (cl_object)(& name ## _data)
#define ecl_def_ct_double_float(name,f,static,const) \
static const struct ecl_doublefloat name ## _data = { \
(int8_t)t_doublefloat, 0, 0, 0, \
(double)(f) }; \
#define ecl_def_ct_double_float(name,f,static,const) \
static const struct ecl_doublefloat name ## _data = { \
(int8_t)t_doublefloat, 0, 0, 0, \
(double)(f) }; \
static const cl_object name = (cl_object)(& name ## _data)
#define ecl_def_ct_long_float(name,f,static,const) \

View file

@ -62,13 +62,7 @@
# include <windows.h>
# endif
# ifdef ECL_THREADS
typedef HANDLE pthread_t;
typedef HANDLE pthread_mutex_t;
typedef HANDLE pthread_cond_t; /*Dummy, not really used*/
# undef ERROR
# ifdef GBC_BOEHM
# define CreateThread GC_CreateThread
# endif
# else
# error "The Windows ports cannot be built without threads."
# endif /* ECL_THREADS */
@ -80,6 +74,7 @@
#endif
#include <ecl/object.h>
#include <ecl/nucleus.h>
#include <ecl/external.h>
#include <ecl/cons.h>
#include <ecl/stacks.h>

View file

@ -64,7 +64,6 @@ struct ecl_c_stack {
* Per-thread data.
*/
typedef struct cl_env_struct *cl_env_ptr;
struct cl_env_struct {
/* Flag for disabling interrupts while we call C library functions. */
volatile int disable_interrupts;
@ -103,7 +102,7 @@ struct cl_env_struct {
/* -- System Processes (native threads) ------------------------------ */
cl_object own_process; /* Backpointer to the host process. */
#ifdef ECL_THREADS
int cleanup;
ecl_thread_t thread;
#endif
/* -- System Interrupts ---------------------------------------------- */
@ -152,6 +151,9 @@ struct ecl_interrupt_struct {
#ifdef ECL_THREADS
ecl_mutex_t signal_queue_lock;
#endif
#ifdef ECL_WINDOWS_THREADS
bool inside_interrupt;
#endif
};
#ifndef __GNUC__
@ -170,9 +172,7 @@ struct ecl_interrupt_struct {
extern ECL_API cl_env_ptr cl_env_p;
#endif
/*
* Per-process data. Modify main.d accordingly.
*/
/* Per-process data. Modify main.d accordingly. */
struct cl_core_struct {
cl_object packages;
@ -189,9 +189,6 @@ struct cl_core_struct {
cl_object c_package;
cl_object ffi_package;
cl_object pathname_translations;
cl_object library_pathname;
cl_object terminal_io;
cl_object null_stream;
cl_object standard_input;
@ -201,97 +198,75 @@ struct cl_core_struct {
cl_object dispatch_reader;
cl_object char_names;
cl_object null_string;
cl_object plus_half;
cl_object minus_half;
cl_object imag_unit;
cl_object minus_imag_unit;
cl_object imag_two;
cl_object singlefloat_zero;
cl_object doublefloat_zero;
cl_object singlefloat_minus_zero;
cl_object doublefloat_minus_zero;
cl_object longfloat_zero;
cl_object longfloat_minus_zero;
cl_object gensym_prefix;
cl_object gentemp_prefix;
cl_object gentemp_counter;
cl_object Jan1st1970UT;
cl_object system_properties;
cl_env_ptr first_env;
#ifdef ECL_THREADS
cl_object processes;
ecl_mutex_t processes_lock;
ecl_mutex_t global_lock;
ecl_mutex_t error_lock;
ecl_rwlock_t global_env_lock;
#endif
cl_object libraries;
size_t max_heap_size;
cl_object bytes_consed;
cl_object gc_counter;
bool gc_stats;
int path_max;
#ifdef GBC_BOEHM
char *safety_region;
#endif
void *default_sigmask;
cl_index default_sigmask_bytes;
#ifdef ECL_THREADS
cl_index last_var_index;
cl_object reused_indices;
#endif
cl_object slash;
cl_object compiler_dispatch;
cl_object rehash_size;
cl_object rehash_threshold;
cl_object known_signals;
};
extern ECL_API struct ecl_type_information ecl_type_info[t_end];
extern ECL_API struct ecl_core_struct ecl_core;
extern ECL_API struct cl_core_struct cl_core;
/* variables */
extern ECL_API cl_object ecl_vr_shandlers;
extern ECL_API cl_object ecl_vr_allow_other_keys;
/* memory.c */
extern ECL_API void *ecl_malloc(cl_index n);
extern ECL_API void *ecl_realloc(void *ptr, cl_index o, cl_index n);
extern ECL_API void ecl_free(void *ptr);
extern ECL_API void ecl_copy(void *dst, void *src, cl_index ndx);
extern ECL_API void ecl_mset(void *dst, byte val, cl_index ndx);
#define ecl_free_unsafe(x) ecl_free(x);
/* alloc.c / alloc_2.c */
/* boot.c */
extern ECL_API int ecl_boot(void);
extern ECL_API int ecl_halt(void);
extern ECL_API const cl_object ecl_ct_Jan1st1970UT;
extern ECL_API const cl_object ecl_ct_null_string;
extern ECL_API const cl_object ecl_ct_default_rehash_size;
extern ECL_API const cl_object ecl_ct_default_rehash_threshold;
extern ECL_API const cl_object ecl_ct_singlefloat_zero;
extern ECL_API const cl_object ecl_ct_doublefloat_zero;
extern ECL_API const cl_object ecl_ct_longfloat_zero;
extern ECL_API const cl_object ecl_ct_singlefloat_minus_zero;
extern ECL_API const cl_object ecl_ct_doublefloat_minus_zero;
extern ECL_API const cl_object ecl_ct_longfloat_minus_zero;
extern ECL_API const cl_object ecl_ct_plus_half;
extern ECL_API const cl_object ecl_ct_minus_half;
extern ECL_API const cl_object ecl_ct_protect_tag;
extern ECL_API const cl_object ecl_ct_dummy_tag;
/* memory */
extern ECL_API cl_object ecl_alloc_object(cl_type t);
extern ECL_API cl_object ecl_alloc_instance(cl_index slots);
extern ECL_API cl_object ecl_alloc_weak_pointer(cl_object o);
extern ECL_API cl_object ecl_alloc_compact_object(cl_type t, cl_index extra_space);
extern ECL_API cl_object ecl_cons(cl_object a, cl_object d);
extern ECL_API void ecl_free_object(cl_object o);
#define ecl_list1(x) ecl_cons(x, ECL_NIL)
extern ECL_API cl_object si_make_weak_pointer(cl_object o);
extern ECL_API cl_object si_weak_pointer_value(cl_object o);
#ifdef GBC_BOEHM
extern ECL_API void *ecl_alloc_unprotected(cl_index n);
extern ECL_API void *ecl_alloc_atomic_unprotected(cl_index n);
extern ECL_API void *ecl_alloc(cl_index n);
extern ECL_API void *ecl_alloc_manual(cl_index n);
extern ECL_API void *ecl_alloc_atomic(cl_index n);
extern ECL_API void *ecl_alloc_uncollectable(size_t size);
extern ECL_API void ecl_free_uncollectable(void *);
extern ECL_API void ecl_dealloc(void *);
#define ecl_alloc_align(s,d) ecl_alloc(s)
#define ecl_alloc_atomic_align(s,d) ecl_alloc_atomic(s)
#else /* Ideally the core would not depend on these. */
# error "IMPLEMENT ME!"
#endif /* GBC_BOEHM */
/* all_symbols */
@ -310,6 +285,7 @@ typedef union {
} cl_symbol_initializer;
extern ECL_API cl_symbol_initializer cl_symbols[];
extern ECL_API cl_index cl_num_symbols_in_core;
extern ECL_API struct ecl_symbol ecl_symbols[];
#define ECL_SYM(name,code) ((cl_object)(cl_symbols+(code)))
@ -328,6 +304,7 @@ extern ECL_API cl_index ecl_atomic_index_incf(cl_index *slot);
/* stack.c */
extern ECL_API cl_object ecl_make_stack(cl_index dim);
extern ECL_API void ecl_free_stack(cl_object o);
extern ECL_API cl_object ecl_stack_push(cl_object stack, cl_object elt);
extern ECL_API cl_object ecl_stack_del(cl_object stack, cl_object elt);
extern ECL_API cl_object ecl_stack_popu(cl_object stack);
@ -572,6 +549,8 @@ extern ECL_API cl_object si_bc_join(cl_object lex, cl_object code, cl_object dat
extern ECL_API cl_object cl_error _ECL_ARGS((cl_narg narg, cl_object eformat, ...)) ecl_attr_noreturn;
extern ECL_API cl_object cl_cerror _ECL_ARGS((cl_narg narg, cl_object cformat, cl_object eformat, ...));
extern ECL_API cl_object ecl_exception_handler(cl_object exception);
extern ECL_API void ecl_internal_error(const char *s) ecl_attr_noreturn;
#ifdef ECL_THREADS
extern ECL_API void ecl_thread_internal_error(const char *s) ecl_attr_noreturn;
@ -579,6 +558,8 @@ extern ECL_API void ecl_thread_internal_error(const char *s) ecl_attr_noreturn;
extern ECL_API void ecl_unrecoverable_error(cl_env_ptr the_env, const char *message) ecl_attr_noreturn;
extern ECL_API void ecl_miscompilation_error(void) ecl_attr_noreturn;
extern ECL_API void ecl_cs_overflow(void) /*ecl_attr_noreturn*/;
extern ECL_API void CEstack_overflow(cl_object resume, cl_object type, cl_object size);
extern ECL_API void FEprogram_error(const char *s, int narg, ...) ecl_attr_noreturn;
extern ECL_API void FEcontrol_error(const char *s, int narg, ...) ecl_attr_noreturn;
extern ECL_API void FEreader_error(const char *s, cl_object stream, int narg, ...) ecl_attr_noreturn;
@ -587,7 +568,10 @@ extern ECL_API void FEerror(const char *s, int narg, ...) ecl_attr_noreturn;
extern ECL_API void FEcannot_open(cl_object fn) ecl_attr_noreturn;
extern ECL_API void FEend_of_file(cl_object strm) ecl_attr_noreturn;
extern ECL_API void FEclosed_stream(cl_object strm) ecl_attr_noreturn;
extern ECL_API void FEunread_stream(cl_object strm, cl_object twice) ecl_attr_noreturn;
extern ECL_API void FEwrong_type_argument(cl_object type, cl_object value) ecl_attr_noreturn;
extern ECL_API void FEwrong_type_pred_arg(cl_object type, cl_object value) ecl_attr_noreturn;
extern ECL_API void FEwrong_type_strm_elt(cl_object type, cl_object value) ecl_attr_noreturn;
extern ECL_API void FEwrong_type_only_arg(cl_object function, cl_object type, cl_object value) ecl_attr_noreturn;
extern ECL_API void FEwrong_type_nth_arg(cl_object function, cl_narg narg, cl_object value, cl_object type) ecl_attr_noreturn;
extern ECL_API void FEwrong_type_key_arg(cl_object function, cl_object keyo, cl_object type, cl_object value) ecl_attr_noreturn;
@ -691,8 +675,20 @@ extern ECL_API cl_object ecl_foreign_data_ref_elt(void *p, enum ecl_ffi_tag type
extern ECL_API void ecl_foreign_data_set_elt(void *p, enum ecl_ffi_tag type, cl_object value);
/* stream.c */
cl_object si_unread_byte(cl_object strm, cl_object byte);
cl_object si_peek_byte(cl_object strm, cl_object eof_value);
extern ECL_API cl_object si_write_char(cl_object strm, cl_object c);
extern ECL_API cl_object si_write_byte(cl_object strm, cl_object c);
extern ECL_API cl_object si_read_char(cl_object strm, cl_object eof_value);
extern ECL_API cl_object si_read_byte(cl_object strm, cl_object eof_value);
extern ECL_API cl_object si_peek_char(cl_object strm, cl_object eof_value);
extern ECL_API cl_object si_peek_byte(cl_object strm, cl_object eof_value);
extern ECL_API cl_object si_unread_char(cl_object strm, cl_object c);
extern ECL_API cl_object si_unread_byte(cl_object strm, cl_object byte);
extern ECL_API cl_object si_listen(cl_object strm);
extern ECL_API cl_object si_clear_input(cl_object strm);
extern ECL_API cl_object si_finish_output(cl_object strm);
extern ECL_API cl_object si_force_output(cl_object strm);
extern ECL_API cl_object si_clear_output(cl_object strm);
/* file.c */
@ -735,6 +731,8 @@ extern ECL_API cl_object cl_file_string_length(cl_object stream, cl_object strin
extern ECL_API cl_object si_do_write_sequence(cl_object string, cl_object stream, cl_object start, cl_object end);
extern ECL_API cl_object si_do_read_sequence(cl_object string, cl_object stream, cl_object start, cl_object end);
extern ECL_API cl_object si_file_column(cl_object strm);
extern ECL_API cl_object si_file_position_get(cl_object strm);
extern ECL_API cl_object si_file_position_set(cl_object strm, cl_object position);
extern ECL_API cl_object cl_interactive_stream_p(cl_object strm);
#if defined(ECL_MS_WINDOWS_HOST)
extern ECL_API cl_object si_windows_codepage_encoding();
@ -749,6 +747,8 @@ extern ECL_API bool ecl_interactive_stream_p(cl_object strm);
extern ECL_API cl_object ecl_open_stream(cl_object fn, enum ecl_smmode smm, cl_object if_exists, cl_object if_does_not_exist, cl_fixnum byte_size, int flags, cl_object external_format);
extern ECL_API cl_object ecl_make_string_input_stream(cl_object strng, cl_index istart, cl_index iend);
extern ECL_API cl_object ecl_make_string_output_stream(cl_index line_length, int extended);
extern ECL_API cl_index ecl_read_byte8(cl_object strm, unsigned char *c, cl_index n);
extern ECL_API cl_index ecl_write_byte8(cl_object strm, unsigned char *c, cl_index n);
extern ECL_API cl_object ecl_read_byte(cl_object strm);
extern ECL_API void ecl_write_byte(cl_object byte, cl_object strm);
extern ECL_API void ecl_unread_byte(cl_object byte, cl_object strm);
@ -1010,7 +1010,7 @@ typedef enum {
} ecl_option;
extern ECL_API const char *ecl_self;
extern ECL_API void ecl_set_option(int option, cl_fixnum value);
extern ECL_API cl_fixnum ecl_set_option(int option, cl_fixnum value);
extern ECL_API cl_fixnum ecl_get_option(int option);
extern ECL_API int cl_boot(int argc, char **argv);
extern ECL_API void cl_shutdown(void);
@ -1649,6 +1649,8 @@ extern ECL_API __m128d ecl_unbox_double_sse_pack(cl_object value);
extern ECL_API cl_object si_ihs_top(void);
extern ECL_API cl_object si_ihs_fun(cl_object arg);
extern ECL_API cl_object si_ihs_env(cl_object arg);
extern ECL_API cl_object si_ihs_lex(cl_object arg);
extern ECL_API cl_object si_ihs_lcl(cl_object arg);
extern ECL_API cl_object si_ihs_bds(cl_object arg);
extern ECL_API cl_object si_ihs_next(cl_object arg);
extern ECL_API cl_object si_ihs_prev(cl_object arg);
@ -1882,6 +1884,19 @@ extern ECL_API cl_object ecl_make_rwlock(cl_object lock);
#endif /* ECL_THREADS */
/* nucleus/module.c */
extern ECL_API cl_object ecl_add_module(cl_object self);
extern ECL_API cl_object ecl_del_module(cl_object self);
extern ECL_API cl_object ecl_modules_init_env(cl_env_ptr the_env);
extern ECL_API cl_object ecl_modules_free_env(cl_env_ptr the_env);
extern ECL_API cl_object ecl_modules_init_cpu(cl_env_ptr the_env);
extern ECL_API cl_object ecl_modules_free_cpu(cl_env_ptr the_env);
extern ECL_API cl_object ecl_module_no_op_env(cl_env_ptr the_env);
extern ECL_API cl_object ecl_module_no_op_cpu(cl_env_ptr the_env);
extern ECL_API cl_object ecl_module_no_op();
/* time.c */
extern ECL_API cl_object cl_sleep(cl_object z);

View file

@ -23,37 +23,42 @@ extern "C" {
#define unlikely_if(x) if (ecl_unlikely(x))
/* booting */
extern ECL_API cl_object ecl_module_process;
extern ECL_API cl_object ecl_module_stacks;
extern ECL_API cl_object ecl_module_dummy;
extern ECL_API cl_object ecl_module_gc;
extern ECL_API cl_object ecl_module_unixint;
#ifdef ECL_THREADS
extern ECL_API cl_object ecl_module_thread;
#endif
extern ECL_API cl_object ecl_module_bignum;
extern ECL_API cl_object ecl_module_ffi;
extern ECL_API cl_object ecl_module_aux;
extern void init_memory(void);
extern void init_all_symbols(void);
extern void init_alloc(int pass);
extern void init_backq(void);
extern void init_big();
extern void init_clos(void);
extern void init_error(void);
extern void init_eval(void);
extern void init_file(void);
#ifndef GBC_BOEHM
extern void init_GC(void);
#endif
extern void init_gc(void);
extern void init_macros(void);
extern void init_read(void);
extern cl_object init_stacks(cl_env_ptr);
extern cl_object free_stacks(cl_env_ptr);
extern void init_unixint(int pass);
extern void init_unixtime(void);
extern void init_compiler(void);
extern void init_process(void);
#ifdef ECL_THREADS
extern void init_threads(void);
#endif
extern void init_modules(void);
extern void ecl_init_env(cl_env_ptr);
extern void init_lib_LSP(cl_object);
extern void free_modules(void);
extern cl_env_ptr _ecl_alloc_env(cl_env_ptr parent);
extern void _ecl_dealloc_env(cl_env_ptr);
/* alloc.d/alloc_2.d */
/* mem_gc.d */
#ifdef GBC_BOEHM
#define ECL_COMPACT_OBJECT_EXTRA(x) ((void*)((x)->array.displaced))
@ -411,8 +416,8 @@ cl_object si_finish_output(cl_object strm);
cl_object si_force_output(cl_object strm);
cl_object si_clear_output(cl_object strm);
#define ecl_unread_error(s) FEerror("Error when unreading to stream ~D", 1, s)
#define ecl_unread_twice(s) FEerror("Unread twice twice to stream ~D", 1, s)
#define ecl_unread_error(s) ecl_ferror(ECL_EX_STRM_UNREAD, strm, ECL_NIL);
#define ecl_unread_twice(s) ecl_ferror(ECL_EX_STRM_UNREAD, strm, ECL_T);
/* streams/strm_common.d */
cl_object ecl_not_a_file_stream(cl_object strm);
@ -597,8 +602,8 @@ extern cl_object _ecl_long_double_to_integer(long double d);
extern cl_fixnum ecl_option_values[ECL_OPT_LIMIT+1];
extern void ecl_init_bignum_registers(cl_env_ptr env);
extern void ecl_clear_bignum_registers(cl_env_ptr env);
extern cl_object ecl_init_bignum_registers(cl_env_ptr env);
extern cl_object ecl_free_bignum_registers(cl_env_ptr env);
/* threads/mutex.d */
@ -691,13 +696,6 @@ extern void ecl_cs_set_size(cl_env_ptr env, cl_index n);
#ifdef ECL_THREADS
extern ECL_API cl_object mp_suspend_loop();
extern ECL_API cl_object mp_break_suspend_loop();
# ifdef ECL_WINDOWS_THREADS
# define ecl_thread_exit() ExitThread(0);
# else
# define ecl_thread_exit() pthread_exit(NULL);
# endif /* ECL_WINDOWS_THREADS */
#endif
/* time.d */
@ -711,7 +709,7 @@ extern void ecl_get_internal_real_time(struct ecl_timeval *time);
extern void ecl_get_internal_run_time(struct ecl_timeval *time);
extern void ecl_musleep(double time);
#define UTC_time_to_universal_time(x) ecl_plus(ecl_make_integer(x),cl_core.Jan1st1970UT)
#define UTC_time_to_universal_time(x) ecl_plus(ecl_make_integer(x),ecl_ct_Jan1st1970UT)
extern cl_fixnum ecl_runtime(void);
/* unixfsys.d */
@ -867,9 +865,30 @@ extern void ecl_interrupt_process(cl_object process, cl_object function);
#include <ecl/threads.h>
/* sigmask */
#ifdef HAVE_SIGPROCMASK
# include <signal.h>
# ifdef ECL_THREADS
static inline int
ecl_sigmask(int how, const sigset_t *set, sigset_t *oldset)
{
return pthread_sigmask(how, set, oldset);
}
# else
static inline int
ecl_sigmask(int how, const sigset_t *set, sigset_t *oldset)
{
return sigprocmask(how, set, oldset);
}
# endif
#endif
/* global locks */
#ifdef ECL_THREADS
# define ECL_WITH_GLOBAL_LOCK_BEGIN(the_env) \
ECL_WITH_NATIVE_LOCK_BEGIN(the_env, &cl_core.global_lock)
# define ECL_WITH_GLOBAL_LOCK_BEGIN(the_env) \
ECL_WITH_NATIVE_LOCK_BEGIN(the_env, &ecl_core.global_lock)
# define ECL_WITH_GLOBAL_LOCK_END \
ECL_WITH_NATIVE_LOCK_END
# define ECL_WITH_LOCK_BEGIN(the_env,lock) { \
@ -894,21 +913,21 @@ extern void ecl_interrupt_process(cl_object process, cl_object function);
ECL_UNWIND_PROTECT_THREAD_SAFE_EXIT { \
ecl_mutex_unlock(__ecl_the_lock); \
} ECL_UNWIND_PROTECT_THREAD_SAFE_END; }
# define ECL_WITH_GLOBAL_ENV_RDLOCK_BEGIN(the_env) { \
const cl_env_ptr __ecl_pack_env = the_env; \
# define ECL_WITH_GLOBAL_ENV_RDLOCK_BEGIN(the_env) { \
const cl_env_ptr __ecl_pack_env = the_env; \
ecl_bds_bind(__ecl_pack_env, ECL_INTERRUPTS_ENABLED, ECL_NIL); \
ecl_rwlock_lock_read(&cl_core.global_env_lock);
# define ECL_WITH_GLOBAL_ENV_RDLOCK_END \
ecl_rwlock_unlock_read(&cl_core.global_env_lock); \
ecl_bds_unwind1(__ecl_pack_env); \
ecl_rwlock_lock_read(&ecl_core.global_env_lock);
# define ECL_WITH_GLOBAL_ENV_RDLOCK_END \
ecl_rwlock_unlock_read(&ecl_core.global_env_lock); \
ecl_bds_unwind1(__ecl_pack_env); \
ecl_check_pending_interrupts(__ecl_pack_env); }
# define ECL_WITH_GLOBAL_ENV_WRLOCK_BEGIN(the_env) { \
const cl_env_ptr __ecl_pack_env = the_env; \
ecl_bds_bind(__ecl_pack_env, ECL_INTERRUPTS_ENABLED, ECL_NIL); \
ecl_rwlock_lock_write(&cl_core.global_env_lock);
# define ECL_WITH_GLOBAL_ENV_WRLOCK_END \
ecl_rwlock_unlock_write(&cl_core.global_env_lock); \
ecl_bds_unwind1(__ecl_pack_env); \
ecl_rwlock_lock_write(&ecl_core.global_env_lock);
# define ECL_WITH_GLOBAL_ENV_WRLOCK_END \
ecl_rwlock_unlock_write(&ecl_core.global_env_lock); \
ecl_bds_unwind1(__ecl_pack_env); \
ecl_check_pending_interrupts(__ecl_pack_env); }
#else
# define ECL_WITH_GLOBAL_LOCK_BEGIN(the_env)

View file

@ -6,4 +6,72 @@
#include "external.h"
struct ecl_core_struct {
cl_env_ptr first_env;
#ifdef ECL_THREADS
cl_object threads;
ecl_mutex_t processes_lock;
ecl_mutex_t global_lock;
ecl_mutex_t error_lock;
ecl_rwlock_t global_env_lock;
cl_index last_var_index;
cl_object reused_indices;
#endif
struct ecl_allocator_ops *allocator;
size_t max_heap_size;
cl_object bytes_consed;
cl_object gc_counter;
bool gc_stats;
char *safety_region;
cl_index default_sigmask_bytes;
cl_object known_signals;
int path_max;
cl_object pathname_translations;
cl_object modules;
cl_object libraries;
cl_object library_pathname;
};
/* process.c */
cl_env_ptr ecl_adopt_cpu();
cl_env_ptr ecl_spawn_cpu();
void ecl_disown_cpu();
/* control.c */
void ecl_escape(cl_object continuation) ecl_attr_noreturn;
cl_object ecl_signal(cl_object condition, cl_object returns, cl_object thread);
cl_object ecl_call_with_handler(cl_object handler, cl_object continuation);
/* Binding a handler conses a new list, but at this stage we don't assume the
the garbage collector to work! Luckily the extent of the binding is dynamic
and we can allocate cons on the stack. */
#define ECL_WITH_HANDLER_BEGIN(the_env, handler) do { \
const cl_env_ptr __the_env = the_env; \
cl_object __ecl_sym = ECL_SIGNAL_HANDLERS; \
cl_object __ecl_hnd = ECL_SYM_VAL(__the_env, __ecl_sym); \
cl_object __ecl_hnds = ecl_cons_stack(handler, __ecl_hnd); \
ecl_bds_bind(__the_env, __ecl_sym, __ecl_hnds);
#define ECL_WITH_HANDLER_END ecl_bds_unwind1(__the_env); } while(0)
cl_object ecl_raise(ecl_ex_type t, bool ret,
cl_object a1, cl_object a2, cl_object a3, void *a4);
#define ecl_ferror ecl_ferror3
#define ecl_ferror1(extype) ecl_raise(extype, 0, ECL_NIL, ECL_NIL, ECL_NIL, NULL)
#define ecl_ferror2(extype,a1) ecl_raise(extype, 0, a1, ECL_NIL, ECL_NIL, NULL)
#define ecl_ferror3(extype,a1,a2) ecl_raise(extype, 0, a1, a2, ECL_NIL, NULL)
#define ecl_ferror4(extype,a1,a2,a3) ecl_raise(extype, 0, a1, a2, a3, NULL)
#define ecl_ferror5(extype,a1,a2,a3,p4) ecl_raise(extype, 0, a1, a2, a3, p4)
#define ecl_cerror ecl_cerror3
#define ecl_cerror1(extype) ecl_raise(extype, 1, ECL_NIL, ECL_NIL, ECL_NIL, NULL)
#define ecl_cerror2(extype,a1) ecl_raise(extype, 1, a1, ECL_NIL, ECL_NIL, NULL)
#define ecl_cerror3(extype,a1,a2) ecl_raise(extype, 1, a1, a2, ECL_NIL, NULL)
#define ecl_cerror4(extype,a1,a2,a3) ecl_raise(extype, 1, a1, a2, a3, NULL)
#define ecl_cerror5(extype,a1,a2,a3,p4) ecl_raise(extype, 1, a1, a2, a3, p4)
#endif /* ECL_NUCLEUS_H */

View file

@ -84,6 +84,8 @@ typedef enum {
t_codeblock,
t_foreign,
t_frame,
t_exception,
t_module,
t_weak_pointer,
#ifdef ECL_SSE2
t_sse_pack,
@ -94,15 +96,33 @@ typedef enum {
FREE = 127 /* free object */
} cl_type;
/*
Definition of the type of LISP objects.
*/
typedef union cl_lispunion *cl_object;
typedef struct cl_env_struct *cl_env_ptr;
typedef cl_object cl_return;
typedef cl_fixnum cl_narg;
typedef cl_object (*cl_objectfn)(cl_narg narg, ...);
typedef cl_object (*cl_objectfn_fixed)();
typedef cl_object (*cl_objectfn_envfn)(cl_env_ptr);
/* Allocator interface */
struct ecl_allocator_ops {
void *(*allocate_memory)(cl_index n); /* low-level alloc */
void *(*allocate_manual)(cl_index n); /* low-level alloc */
void *(*allocate_atomic)(cl_index n); /* low-level alloc */
cl_object (*allocate_object)(cl_type t); /* high-level alloc */
void (*free_memory)(void*); /* low-level free */
void (*free_object)(cl_object); /* high-level free */
};
struct ecl_type_information {
cl_type t;
const char * name;
size_t size;
uintmax_t descriptor;
};
/*
OBJect NULL value.
@ -258,16 +278,20 @@ enum ecl_stype { /* symbol type */
};
#define ECL_NIL ((cl_object)t_list)
#define ECL_NIL_SYMBOL ((cl_object)cl_symbols)
#define ECL_T ((cl_object)(cl_symbols+1))
#define ECL_UNBOUND ((cl_object)(cl_symbols+2))
#define ECL_PROTECT_TAG ((cl_object)(cl_symbols+3))
#define ECL_DUMMY_TAG ((cl_object)(cl_symbols+4))
#define ECL_RESTART_CLUSTERS ((cl_object)(cl_symbols+5))
#define ECL_HANDLER_CLUSTERS ((cl_object)(cl_symbols+6))
#define ECL_INTERRUPTS_ENABLED ((cl_object)(cl_symbols+7))
#define ECL_NO_TL_BINDING ((cl_object)(1 << ECL_TAG_BITS))
#define ECL_PROTECT_TAG ecl_ct_protect_tag
#define ECL_DUMMY_TAG ecl_ct_dummy_tag
#define ECL_SIGNAL_HANDLERS ((cl_object)(ecl_symbols+0))
#define ECL_RESTART_CLUSTERS ((cl_object)(ecl_symbols+1))
#define ECL_INTERRUPTS_ENABLED ((cl_object)(ecl_symbols+2))
#define ECL_ALLOW_OTHER_KEYS ((cl_object)(ecl_symbols+3))
#define ECL_T ((cl_object)(ecl_symbols+4))
#define ECL_UNBOUND ((cl_object)(ecl_symbols+5))
#define ECL_NIL_SYMBOL ((cl_object)(cl_symbols+0))
struct ecl_symbol {
_ECL_HDR1(stype); /* symbol type */
cl_object value; /* global value of the symbol */
@ -574,6 +598,7 @@ enum ecl_smmode { /* stream mode */
ecl_smm_string_input, /* string input */
ecl_smm_string_output, /* string output */
ecl_smm_probe, /* probe (only used in open_stream()) */
ecl_smm_other, /* custom stream implementation */
#if defined(ECL_WSOCK)
ecl_smm_input_wsock, /* input socket (Win32) */
ecl_smm_output_wsock, /* output socket (Win32) */
@ -946,6 +971,65 @@ struct ecl_stack_frame {
struct cl_env_struct *env;
};
typedef enum {
ECL_EX_FERROR, /* general purpose fatal error */
ECL_EX_CERROR, /* general purpose continuable error */
ECL_EX_CS_OVR, /* stack overflow */
ECL_EX_FRS_OVR, /* stack overflow */
ECL_EX_BDS_OVR, /* stack overflow */
ECL_EX_BADARG, /* wrong type of argument */
ECL_EX_BADARG_ONLY, /* wrong type of the only argument */
ECL_EX_UNSATISFIED, /* wrong type of argument (predicate) */
ECL_EX_EOF, /* end of file */
ECL_EX_NIY, /* not implemented yet */
ECL_EX_NAO, /* not applicable operation */
ECL_EX_STRM_BADELT, /* invalid stream element type */
ECL_EX_STRM_CLOSED, /* the stream is closed */
ECL_EX_STRM_UNREAD, /* error while unreading into the stream */
/* Kludges for the bytecodes VM */
ECL_EX_VM_BADARG_EXCD,
ECL_EX_VM_BADARG_UNKK,
ECL_EX_VM_BADARG_ODDK,
ECL_EX_VM_BADARG_NTH_VAL,
ECL_EX_VM_BADARG_ENDP,
ECL_EX_VM_BADARG_CAR,
ECL_EX_VM_BADARG_CDR,
ECL_EX_VM_BADARG_PROGV,
/* Specific normal conditions */
ECL_EX_V_CSETQ, /* assigning a constant */
ECL_EX_V_CBIND, /* binding a constant */
ECL_EX_V_UNBND, /* unbound variable */
ECL_EX_V_BNAME, /* illegal variable name */
ECL_EX_F_NARGS, /* wrong number of arguments */
ECL_EX_F_UNDEF, /* undefined function */
ECL_EX_F_INVAL, /* non-function passed as function */
ECL_EX_S_FMISS /* missing unwind frame (ecl_escape) */
} ecl_ex_type;
#define ECL_EXCEPTIONP(x) ((ECL_IMMEDIATE(x)==0) && ((x)->d.t==t_exception))
struct ecl_exception {
_ECL_HDR1(ex_type);
/* Slots for storing contextual data. Depends on the exception type. */
cl_object arg1; /* usually the offending object or the type. */
cl_object arg2; /* usually additional arguments or the flag. */
cl_object arg3; /* arbitrary lisp extra argument (i.e ECL_NIL). */
void * arg4; /* arbitrary last ditch argument (usually NULL). */
};
struct ecl_module {
_ECL_HDR;
cl_object name;
cl_objectfn_fixed create;
cl_objectfn_fixed enable;
cl_objectfn_envfn init_env;
cl_objectfn_envfn init_cpu;
cl_objectfn_envfn free_cpu;
cl_objectfn_envfn free_env;
cl_objectfn_fixed disable;
cl_objectfn_fixed destroy;
};
struct ecl_weak_pointer { /* weak pointer to value */
_ECL_HDR;
cl_object value;
@ -1000,18 +1084,15 @@ struct ecl_process {
_ECL_HDR;
cl_object name;
cl_object function;
cl_objectfn entry; /* entry address (matches ecl_cfun offset) */
cl_object args;
struct cl_env_struct *env;
cl_object interrupt;
cl_object inherit_bindings_p;
cl_object parent;
cl_object exit_values;
cl_object woken_up;
ecl_mutex_t start_stop_lock; /* phase is updated only when we hold this lock */
ecl_cond_var_t exit_barrier; /* process-join waits on this barrier */
cl_index phase;
ecl_thread_t thread;
int trap_fpe_bits;
struct cl_env_struct *env;
};
enum {
@ -1174,6 +1255,8 @@ union cl_lispunion {
struct ecl_cclosure cclosure; /* compiled closure */
struct ecl_dummy d; /* dummy */
struct ecl_instance instance; /* clos instance */
struct ecl_exception exception; /* exception */
struct ecl_module module; /* core module */
#ifdef ECL_THREADS
struct ecl_process process; /* process */
struct ecl_lock lock; /* lock */

View file

@ -14,11 +14,10 @@
#ifndef ECL_STACK_RESIZE_H
#define ECL_STACK_RESIZE_H
/* We can't block interrupts with ecl_disable_interrupts() and write
* in the thread local environment if we use fast interrupt dispatch
* via mprotect(), so we have to use sigprocmask instead. No
* performance problems, since this is only used for stack
* resizing. */
/* We can't block interrupts with ecl_disable_interrupts() and write in the
* thread local environment if we use fast interrupt dispatch via mprotect(), so
* we have to use sigprocmask instead. No performance problems, since this is
* only used for stack resizing. */
#if defined(ECL_THREADS) && defined(ECL_USE_MPROTECT)
# ifdef HAVE_SIGPROCMASK
# include <signal.h>

View file

@ -233,16 +233,18 @@ typedef struct ecl_ihs_frame {
struct ecl_ihs_frame *next;
cl_object function;
cl_object lex_env;
cl_object lcl_env;
cl_index index;
cl_index bds;
} *ecl_ihs_ptr;
#define ecl_ihs_push(env,rec,fun,lisp_env) do { \
#define ecl_ihs_push(env,rec,fun,lex,lcl) do { \
const cl_env_ptr __the_env = (env); \
ecl_ihs_ptr const r = (ecl_ihs_ptr const)(rec); \
r->next=__the_env->ihs_stack.top; \
r->function=(fun); \
r->lex_env=(lisp_env); \
r->lex_env=(lex); \
r->lcl_env=(lcl); \
r->index=__the_env->ihs_stack.top->index+1; \
r->bds=__the_env->bds_stack.top - __the_env->bds_stack.org; \
__the_env->ihs_stack.top = r; \
@ -508,7 +510,7 @@ ecl_data_stack_set_index(cl_env_ptr env, cl_index ndx)
#define ECL_HANDLER_CASE_BEGIN(the_env, names) do { \
const cl_env_ptr __the_env = (the_env); \
const cl_object __ecl_tag = ecl_list1(names); \
ecl_bds_bind(__the_env, ECL_HANDLER_CLUSTERS, \
ecl_bds_bind(__the_env, ECL_SIGNAL_HANDLERS, \
si_bind_simple_handlers(__ecl_tag, names)); \
ecl_frs_push(__the_env,__ecl_tag); \
if (__ecl_frs_push_result == 0) {

View file

@ -22,8 +22,8 @@
# endif
#endif
#ifndef ECL_MUTEX_H
#define ECL_MUTEX_H
#ifndef ECL_THREADS_H
#define ECL_THREADS_H
#include <errno.h>
#ifdef ECL_WINDOWS_THREADS
@ -38,6 +38,45 @@
#endif
#include <math.h>
#ifdef ECL_WINDOWS_THREADS
/* Windows can't into typedefs in parameter lists. */
/* typedef DWORD WINAPI (*ecl_thread_entry)(void *ptr); */
static inline int
ecl_thread_create(cl_env_ptr the_env, /* ecl_thread_entry */ void* fun)
{
HANDLE code;
DWORD threadId;
code = (HANDLE)CreateThread(NULL, 0, fun, the_env, 0, &threadId);
the_env->thread = code;
/* NULL handle is a failure. */
return (code != NULL) ? 0 : 1;
}
static inline void
ecl_thread_exit()
{
ExitThread(0);
}
#else /* ECL_WINDOWS_THREADS */
typedef void* (*ecl_thread_entry)(void *ptr);
static inline int
ecl_thread_create(cl_env_ptr the_env, ecl_thread_entry fun)
{
pthread_attr_t pthreadattr;
pthread_attr_init(&pthreadattr);
pthread_attr_setdetachstate(&pthreadattr, PTHREAD_CREATE_DETACHED);
return pthread_create(&the_env->thread, &pthreadattr, fun, the_env);
}
static inline void
ecl_thread_exit()
{
pthread_exit(NULL);
}
#endif /* ECL_WINDOWS_THREADS */
#if !defined(ECL_WINDOWS_THREADS)
#define ECL_MUTEX_SUCCESS 0
@ -734,6 +773,6 @@ ecl_rwlock_lock_write(ecl_rwlock_t *rwlock)
#endif /* ECL_WINDOWS_THREADS */
#endif /* ECL_MUTEX_H */
#endif /* ECL_THREADS_H */
#endif /* ECL_THREADS */

View file

@ -26,7 +26,8 @@
(defparameter *quit-tag* (cons nil nil))
(defparameter *quit-tags* nil)
(defparameter *break-level* 0) ; nesting level of error loops
(defparameter *break-env* nil)
(defparameter *break-lexenv* nil)
(defparameter *break-locals* nil)
(defparameter *ihs-base* 0)
(defparameter *ihs-top* (ihs-top))
(defparameter *ihs-current* 0)
@ -601,7 +602,7 @@ Use special code 0 to cancel this operation.")
(tpl-prompt)
(tpl-read))
values (multiple-value-list
(eval-with-env - *break-env*))
(eval-with-env - *break-lexenv*))
/// // // / / values *** ** ** * * (car /))
(tpl-format "~&~{~s~^~%~}~%" values)))))
(loop
@ -904,76 +905,106 @@ Use special code 0 to cancel this operation.")
@(return) = CONS(name,output);
" :one-liner nil))
(defun decode-ihs-env (*break-env*)
(let ((env *break-env*))
(if (vectorp env)
#+ecl-min
nil
#-ecl-min
(let* ((next (decode-ihs-env
(ffi:c-inline (env) (:object) :object
"(#0)->vector.self.t[0]" :one-liner t))))
(nreconc (loop with l = (- (length env) 2)
for i from 0 below l
do (push (decode-env-elt env i) next))
next))
env)))
;;; This function is here for backward compatibility. We also extend it to
;;; "simply work" with ihs indexes - then it decodes both locals and lexenv.
(defun decode-ihs-env (env)
(etypecase env
((or vector si:frame)
(decode-ihs-locals env))
(integer
(append (decode-ihs-locals (ihs-lcl env))
(decode-ihs-lexenv (ihs-lex env))))
(null
nil)))
(defun decode-ihs-locals (env)
#+ecl-min nil
#-ecl-min
(etypecase env
(vector
(let ((next (decode-ihs-locals
(ffi:c-inline (env) (:object) :object
"(#0)->vector.self.t[0]" :one-liner t))))
(nreconc (loop with l = (- (length env) 2)
for i from 0 below l
do (push (decode-env-elt env i) next))
next)))
(si:frame
(let* ((lcls '()))
(ffi:c-inline (env lcls) (:object :object) :void
"loop_across_frame_fifo(elt, (#0)) {
(#1)=ecl_cons(elt, (#1));
} end_loop_across_frame();")
lcls))
(null
nil)))
(defun decode-ihs-lexenv (env)
#+ecl-min nil
#-ecl-min
(etypecase env
(vector
(loop for elt across env collect elt))
(null
nil)))
(defun ihs-environment (ihs-index)
(labels ((newly-bound-special-variables (bds-min bds-max)
(loop for i from bds-min to bds-max
for variable = (bds-var i)
unless (member variable output :test #'eq)
collect variable into output
finally (return output)))
(special-variables-alist (ihs-index)
(let ((top (ihs-top)))
(unless (> ihs-index top)
(let* ((bds-min (1+ (ihs-bds ihs-index)))
(bds-top (bds-top))
(bds-max (if (= ihs-index top)
bds-top
(ihs-bds (1+ ihs-index))))
(variables (newly-bound-special-variables bds-min bds-max)))
(loop with output = '()
for i from (1+ bds-max) to bds-top
for var = (bds-var i)
when (member var variables :test #'eq)
do (setf variables (delete var variables)
output (acons var (bds-val i) output))
finally (return
(append (loop for v in variables
collect (cons v (symbol-value v)))
output)))))))
(extract-restarts (variables-alist)
(let ((record (assoc '*restart-clusters* variables-alist)))
(if record
(let* ((bindings (cdr record))
(new-bindings (first bindings)))
(values (delete record variables-alist) new-bindings))
(values variables-alist nil)))))
(let* ((functions '())
(blocks '())
(local-variables '())
(special-variables '())
(restarts '())
record0 record1)
(dolist (record (decode-ihs-env (ihs-env ihs-index)))
(cond ((atom record)
(push (compiled-function-name record) functions))
((progn
(setf record0 (car record) record1 (cdr record))
(when (stringp record0)
(setf record0
(let ((*package* (find-package "KEYWORD")))
(with-standard-io-syntax
(read-from-string record0)))))
(or (symbolp record0) (stringp record0)))
(setq local-variables (acons record0 record1 local-variables)))
((symbolp record1)
(push record1 blocks))
(t
)))
(let ((functions '())
(blocks '())
(local-variables '())
(special-variables '())
(restarts '())
record0 record1)
(labels ((newly-bound-special-variables (bds-min bds-max)
(loop for i from bds-min to bds-max
for variable = (bds-var i)
unless (member variable output :test #'eq)
collect variable into output
finally (return output)))
(special-variables-alist (ihs-index)
(let ((top (ihs-top)))
(unless (> ihs-index top)
(let* ((bds-min (1+ (ihs-bds ihs-index)))
(bds-top (bds-top))
(bds-max (if (= ihs-index top)
bds-top
(ihs-bds (1+ ihs-index))))
(variables (newly-bound-special-variables bds-min bds-max)))
(loop with output = '()
for i from (1+ bds-max) to bds-top
for var = (bds-var i)
when (member var variables :test #'eq)
do (setf variables (delete var variables)
output (acons var (bds-val i) output))
finally (return
(append (loop for v in variables
collect (cons v (symbol-value v)))
output)))))))
(extract-restarts (variables-alist)
(let ((record (assoc '*restart-clusters* variables-alist)))
(if record
(let* ((bindings (cdr record))
(new-bindings (first bindings)))
(values (delete record variables-alist) new-bindings))
(values variables-alist nil))))
(process-env-record (record)
(cond ((atom record)
(push (compiled-function-name record) functions))
((progn
(setf record0 (car record) record1 (cdr record))
(when (stringp record0)
(setf record0
(let ((*package* (find-package "KEYWORD")))
(with-standard-io-syntax
(read-from-string record0)))))
(or (symbolp record0) (stringp record0)))
(setq local-variables (acons record0 record1 local-variables)))
((symbolp record1)
(push record1 blocks))
(t
))))
(map nil #'process-env-record (decode-ihs-locals (ihs-lcl ihs-index)))
(map nil #'process-env-record (decode-ihs-lexenv (ihs-lex ihs-index)))
(multiple-value-bind (special-variables restarts)
(extract-restarts (special-variables-alist ihs-index))
(values (nreverse local-variables)
@ -1017,7 +1048,7 @@ Use special code 0 to cancel this operation.")
(defun tpl-inspect-command (var-name)
(when (symbolp var-name)
(setq var-name (symbol-name var-name)))
(let ((val-pair (assoc var-name (decode-ihs-env *break-env*)
(let ((val-pair (assoc var-name (decode-ihs-locals *break-locals*)
:test #'(lambda (s1 s2)
(when (symbolp s2) (setq s2 (symbol-name s2)))
(if (stringp s2)
@ -1204,7 +1235,8 @@ Use special code 0 to cancel this operation.")
(set-break-env))
(defun set-break-env ()
(setq *break-env* (ihs-env *ihs-current*)))
(setq *break-lexenv* (ihs-lex *ihs-current*))
(setq *break-locals* (ihs-lcl *ihs-current*)))
(defun ihs-search (string unrestricted &optional (start (si::ihs-top)))
(do ((ihs start (si::ihs-prev ihs)))
@ -1300,7 +1332,8 @@ Use the following functions to directly access ECL stacks.
Invocation History Stack:
(SYS:IHS-TOP) Returns the index of the TOP of the IHS.
(SYS:IHS-FUN i) Returns the function of the i-th entity in IHS.
(SYS:IHS-ENV i)
(SYS:IHS-LEX i) Returns the lexical environment of the i-th entry in IHS.
(SYS:IHS-LCL i) Returns the local environment of the i-th entry in IHS.
(SYS:IHS-PREV i)
(SYS:IHS-NEXT i)
@ -1413,7 +1446,8 @@ package."
(*break-condition* condition)
(*break-level* (1+ *break-level*))
(break-level *break-level*)
(*break-env* nil))
(*break-locals* nil)
(*break-lexenv* nil))
(check-default-debugger-runaway)
#+threads
;; We give our process priority for grabbing the console.

View file

@ -192,7 +192,7 @@
;;; Fixed: 10/10/2006
;;; Description:
;;;
;;; Nested calls to queue_finalizer trashed the value of cl_core.to_be_finalized
;;; Nested calls to queue_finalizer trashed the value of ecl_core.to_be_finalized
;;; The following code tests that at least three objects are finalized.
;;;
;;; Note: this test fails in multithreaded mode. GC takes too long!

182
src/util/nucleus.org Normal file
View file

@ -0,0 +1,182 @@
* Runtime
When we initialize ECL we need to take care of a few things. First we need to
recognize the distinction between different environments:
- ecl_core and cl-core structures are global and shared by all processes
- cl_env_struct is local to each process/thread
Note that currently we don't put a hard distinction between processes and
threads, but in the near future I plan to separate them in N-to-M scheme.
That's why I'm going to treat them as distinct in this overview.
In other words:
- current :: ~[core] 1-n [process] 1-1 [environment]~.
- planned :: ~[core] 1-n [process] 1-n [environment]~.
Sometimes I'll use the word ~cpu~ in place of ~process~ and ~env~ in place of
~environment~.
First, when the program starts, we need to initialize the global state, adopt
the current process and associate the first environment with it. That creates a
single computation context that will be used for further initialization.
To allow loose coupling of components we introduce the concept of modules. Each
module implements a certain aspect of the system and is initialized separately
in each context: core, process and thread. When we leave the context (i.e the
thread exits, or we disown the cpu) a matching "release" procedure is called.
#+begin_src lisp
(defstruct module
create destroy
enable disable
init_cpu free_cpu
init_env init_env)
#+end_src
Not all options make sense for each module -- in that case a no-op function is
used. To avoid the situation where we need to retroactively initialize a module
for pre-existing processes and environments, all modules must be added before we
start using the first process.
- create :: initialize global structure
- enable :: start the module
- delete :: stop the module and release all resources
- init_env :: initialization for the current environment
- free_env :: clean up before we destroy the environment
- init_cpu :: initialization for the current process
- free_cpu :: clean up before we destroy the process
It is important to note that the environment is usually initialized on a
different cpu than the one that it runs on. This is to avoid race conditions.
** The core
The core encapsulates the following:
- user defined global options
- a set of modules that need to be initialized
- a set of processes (adopted and spawned)
The initialization requires us to parse user options and initialize modules.
Process manager may be treated as a special module, thus:
#+begin_src lisp
(defun initialize-core ()
(parse-user-options)
(initialize-modules)
(enable :process-module))
(defun initialize-modules ()
(add-module :process-module)
(add-module :c-stack-module)
(add-module :big-num-module)
;; ... (depends on the runtime)
(seal-modules))
(defun add-module (module)
;; Initialize for the first cpu and environment.
(create module)
(init-cpu module +first-env+)
(init-env module +first-env+))
(defun del-module (module)
(disable module)
(free-env module +first-env+)
(free-cpu module +first-env+)
(delete module))
#+end_src
** Processes
#+begin_src lisp
(define-module :process-module
:create #'init-process
:enable #'enable-process)
(defun init-process ()
(initialize-locks :core)
(initialize-self main_thread)
(initialize-tls cl_env_key)
(initialize-env :first-env))
(defun enable-process ()
(dolist (module *modules*)
(init-cpu module)))
#+end_src
** Threads
#+begin_src lisp
(define-module :thread-module
:create #'init-thread
:enable #'enable-thread)
(defun init-thread ()
(error "not implemented yet")
(init-bindings))
(defun enable-thread ()
(dolist (module *modules*)
(init-env module)))
#+end_src
* Early Languages
** F42
f42 is a forth dialect that compiles directly to the bytecodes vm. It is
available very early before a full environment is estabilished. It consists of:
- readtable that reads symbols (case sensitive), strings, fixnums and lists
- character stream using C stream interface (we bind stdin/stdout)
- dictionary with a set of core words and raw bytevm opcodes
- command reader that defines and executes lines of words (commands)
- one pass compiler that takes a line of words and produces bytecodes
Lazy as I am I've added an additional opcode to the bytevm besides OP_QUOTE.
That word is OP_CALLW and it is responsible for calling an immediate word.
Thanks to that bytecodes size will always match the length of the command.
The repl works in two modes: execution mode and compilation mode. Conventionally
the compilation mode is entered by typing the word ~:~ and it is left when after
we type ~;~, for examlpe ~: new-word 42 13 + ;~.
It is important to note that there are no guard rails. If the line contains an
opcode leading segfaults (i.e popping from an empty stack), then it is on you.
| : | start definition | |
| ; | end definition | |
| . | pop from the stack | safe |
| .S | print the stack | |
| .D | print a dictionary | |
| [opcode] | insert an opcode | i.e ~NOP~ |
| [word] | invoke a word | i.e ~foo~ |
This poor dictionary will be extended when deemed necessary. Note that special
operators are catered to by a virtue of embedding opcodes. A dictionary entries
are symbols and a definition is stored as a symbol value.
** UCL
Operator ~defm~ is for defining macros and ~defc~ for defining typed functions
that can be transpiled to C99. ~defl~ as defined below could be used as an
operator that defines functions that may be used with Lisp runtime (value-wise).
#+begin_src scheme
(defm (twice form)
`(progn ,form ,form))
(defn ((hello :void) (name :string) (n :index))
"Prints 'Hello {STRING}' n times."
(do ((i 0) (1+ i))
((>= i times))
(out "Hello " name "\n")))
(defm ((defl . args) . body)
`(defn ,(mapcar (lambda (a) (list a :object)))
,@body))
#+end_src