Skip to content

Commit

Permalink
Delete unimplemented TASK! stub
Browse files Browse the repository at this point in the history
TASK! was an unfinished feature of R3-Alpha.  The basic idea was that
one would be able to do something like a MAKE OBJECT! in which the
object's context variables would be isolated to itself... and it would
run on an independent thread.

Rebol's performance story depended on reuse of several large
preallocated global buffers.  So the plan had been to use thread-local
storage (a feature not standardized until the 2011 C and C++ specs)
to mark these global buffers as being instantiated one per thread.
So if one of these temporary buffers was used in one thread, it would
not trip up another.

That work alone was nowhere near the amount of work required to tell
a coherent multithreading story.  Even at the lowest levels of memory
allocation there was no thread safety.  If two threads tried to do a
memory allocation from the memory pools, they could trip each other
up on the internal pointers used for bookkeeping.  That's to say
nothing of the higher level issues of series management.

Regardless of what the long-term multithreading story is for Rebol
(and Red), it does not seem fitting to expose users to things like
mutexes and semaphores--with the penalty of getting it wrong being a
crashing program.  Hence there is no acceptable path forward for the
stub implementation that was beginning.

The practical way to do what TASK! was doing would be to launch
independent Rebol processes and exchange information between them
(perhaps through something like a ZeroMQ binding).  Because modern
operating systems only load one copy of the code pages when multiple
copies of the same executable are loaded, this would have basically
the same overhead as a working TASK! implementation would have had.

What is *really* needed to help Rebol in the thread department is to
have what the V8 JavaScript engine calls "isolates".  This means
getting rid of the thread-local-storage concept and instead allowing
a single process to hold independent sessions that don't interact
with each other directly.  This is important in order to have a REPL
and debugger that is implemented in Rebol; so that independent
interpreter stacks can be running without interfering with each other.

The other thing that would be a priority would be to stylize the code
in such a way that a garbage collector thread could run concurrently
with the evaluator.  This is a completely different problem.  The
tentative strategy for it would lean heavily on C++; hence the pure
C build would only be able to use "stop the world" garbage collection.
  • Loading branch information
hostilefork committed Oct 20, 2016
1 parent dc06920 commit dfcd893
Show file tree
Hide file tree
Showing 15 changed files with 4 additions and 280 deletions.
1 change: 0 additions & 1 deletion make/CMakeLists.txt
Expand Up @@ -273,7 +273,6 @@ set (CORE_SOURCE
${CORE_DIR}/c-path.c
${CORE_DIR}/c-port.c
${CORE_DIR}/c-signal.c
${CORE_DIR}/c-task.c
${CORE_DIR}/c-word.c
${CORE_DIR}/c-value.c
${CORE_DIR}/d-break.c
Expand Down
1 change: 0 additions & 1 deletion src/boot/types.r
Expand Up @@ -110,7 +110,6 @@ object context * f* * * context
frame context * f* * * context
module context * f* * * context
error context + f+ * * context
task context + + * * context
port port context context context * context

gob gob * * * * -
Expand Down
1 change: 0 additions & 1 deletion src/boot/typespec.r
Expand Up @@ -57,7 +57,6 @@ set-word ["definition of a word's value" word]
string ["string series of characters" string]
struct ["native structure definition" block]
tag ["markup string (HTML or XML)" string]
task ["evaluation environment" context]
time ["time of day or duration" scalar]
tuple ["sequence of small integers (colors, versions, IP)" scalar]
typeset ["set of datatypes" opt-object]
Expand Down
108 changes: 0 additions & 108 deletions src/core/c-task.c

This file was deleted.

1 change: 0 additions & 1 deletion src/core/e-func-symbols.c
Expand Up @@ -129,7 +129,6 @@ const void *rebol_symbols [] = {
SYM_FUNC(Init_Ports), // c-port.c
SYM_FUNC(Shutdown_Ports), // c-port.c
SYM_FUNC(Do_Signals_Throws), // c-signal.c
SYM_FUNC(Do_Task), // c-task.c
#if defined(__cplusplus) && !defined(NDEBUG)
SYM_FUNC(Assert_Cell_Writable), // c-value.c
#endif
Expand Down
3 changes: 0 additions & 3 deletions src/core/m-gc.c
Expand Up @@ -754,9 +754,6 @@ void Queue_Mark_Value_Deep(const RELVAL *val)
Queue_Mark_Array_Deep(VAL_TYPE_SPEC(val));
break;

case REB_TASK: // not yet implemented
fail (Error(RE_MISC));

case REB_OBJECT:
case REB_MODULE:
case REB_PORT:
Expand Down
9 changes: 3 additions & 6 deletions src/core/n-control.c
Expand Up @@ -1089,13 +1089,10 @@ REBNATIVE(do)

f->varlist = CTX_VARLIST(VAL_CONTEXT(value)); // need w/NULL def

return Apply_Frame_Core(f, Canon(SYM___ANONYMOUS__), NULL);
}
return Apply_Frame_Core(f, Canon(SYM___ANONYMOUS__), NULL); }

case REB_TASK:
Do_Task(value);
*D_OUT = *value;
return R_OUT;
default:
break;
}

// Note: it is not possible to write a wrapper function in Rebol
Expand Down
1 change: 0 additions & 1 deletion src/core/s-crc.c
Expand Up @@ -353,7 +353,6 @@ REBCNT Hash_Value(const RELVAL *v, REBCTX *specifier)
ret = cast(REBCNT, cast(REBUPT, VAL_MAP(v)) >> 4);
break;

case REB_TASK:
case REB_GOB:
case REB_EVENT:
case REB_HANDLE:
Expand Down
4 changes: 0 additions & 4 deletions src/core/s-mold.c
Expand Up @@ -1433,10 +1433,6 @@ void Mold_Value(REB_MOLD *mold, const RELVAL *value, REBOOL molded)
else Mold_Object(const_KNOWN(value), mold);
break;

case REB_TASK:
Mold_Object(const_KNOWN(value), mold);
break;

case REB_ERROR:
Mold_Error(const_KNOWN(value), mold, molded);
break;
Expand Down
2 changes: 1 addition & 1 deletion src/include/sys-core.h
Expand Up @@ -342,7 +342,7 @@ enum {

#define TS_NOT_COPIED \
(FLAGIT_KIND(REB_IMAGE) | FLAGIT_KIND(REB_VECTOR) \
| FLAGIT_KIND(REB_TASK) | FLAGIT_KIND(REB_PORT))
| FLAGIT_KIND(REB_PORT))

#define TS_STD_SERIES (TS_SERIES & ~TS_NOT_COPIED)
#define TS_SERIES_OBJ ((TS_SERIES | TS_CONTEXT) & ~TS_NOT_COPIED)
Expand Down
1 change: 0 additions & 1 deletion src/mezz/base-defs.r
Expand Up @@ -105,7 +105,6 @@ eval proc [
frame?:
module?:
error?:
task?:
port?:
gob?:
event?:
Expand Down
9 changes: 0 additions & 9 deletions src/mezz/mezz-func.r
Expand Up @@ -20,15 +20,6 @@ map: func [
]


task: func [
{Creates a task.}
spec [block!] {Name or spec block}
body [block!] {The body block of the task}
][
make task! copy/deep reduce [spec body]
]


body-of: function [
value [any-value!]
][
Expand Down
88 changes: 0 additions & 88 deletions src/os/posix/host-thread.c

This file was deleted.

50 changes: 0 additions & 50 deletions src/os/windows/host-lib.c
Expand Up @@ -626,56 +626,6 @@ CFUNC *OS_Find_Function(void *dll, const char *funcname)
}


//
// OS_Create_Thread: C
//
// Creates a new thread for a REBOL task datatype.
//
// NOTE:
// For this to work, the multithreaded library option is
// needed in the C/C++ code generation settings.
//
// The Task_Ready stops return until the new task has been
// initialized (to avoid unknown new thread state).
//
REBINT OS_Create_Thread(THREADFUNC *init, void *arg, REBCNT stack_size)
{
REBINT thread;

Task_Ready = CreateEvent(NULL, TRUE, FALSE, L"REBOL_Task_Launch");
if (!Task_Ready) return -1;

thread = _beginthread(init, stack_size, arg);

if (thread) WaitForSingleObject(Task_Ready, 2000);
CloseHandle(Task_Ready);

return 1;
}


//
// OS_Delete_Thread: C
//
// Can be called by a REBOL task to terminate its thread.
//
void OS_Delete_Thread(void)
{
_endthread();
}


//
// OS_Task_Ready: C
//
// Used for new task startup to resume the thread that
// launched the new task.
//
void OS_Task_Ready(REBINT tid)
{
SetEvent(Task_Ready);
}

//
// OS_Create_Process: C
//
Expand Down

0 comments on commit dfcd893

Please sign in to comment.