Commit a3270966 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Initial, very broken, implementation of threads

Well, the thread-creating should work, but nothing is threadsafe.
parent d4802e1b
...@@ -472,18 +472,19 @@ CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info, ...@@ -472,18 +472,19 @@ CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info,
const std::string* attr, bool clsonly, ArgPassSpec argspec, const std::string* attr, bool clsonly, ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) { const std::vector<const std::string*>* keyword_names) {
RELEASE_ASSERT(!argspec.has_starargs, ""); bool pass_keywords = (argspec.num_keywords != 0);
RELEASE_ASSERT(!argspec.has_kwargs, ""); int npassed_args = argspec.totalPassed();
RELEASE_ASSERT(argspec.num_keywords == 0, "");
llvm::Value* func; llvm::Value* func;
if (args.size() == 0) if (pass_keywords)
func = g.funcs.callattr;
else if (npassed_args == 0)
func = g.funcs.callattr0; func = g.funcs.callattr0;
else if (args.size() == 1) else if (npassed_args == 1)
func = g.funcs.callattr1; func = g.funcs.callattr1;
else if (args.size() == 2) else if (npassed_args == 2)
func = g.funcs.callattr2; func = g.funcs.callattr2;
else if (args.size() == 3) else if (npassed_args == 3)
func = g.funcs.callattr3; func = g.funcs.callattr3;
else else
func = g.funcs.callattr; func = g.funcs.callattr;
......
// Copyright (c) 2014 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PYSTON_CORE_THREADING_H
#define PYSTON_CORE_THREADING_H
namespace pyston {
namespace threading {
#define THREADING_USE_GIL 0
#define THREADING_SAFE_DATASTRUCTURES 0
void ensureSerial();
void endEnsureSerial();
#if THREADING_USE_GIL
inline void ensureSerial() {
}
inline void endEnsureSerial() {
}
#endif
class SerialRegion {
public:
SerialRegion() { ensureSerial(); }
~SerialRegion() { endEnsureSerial(); }
};
class UnSerialRegion {
public:
UnSerialRegion() { endEnsureSerial(); }
~UnSerialRegion() { ensureSerial(); }
};
void allowThreads();
void endAllowThreads();
class AllowThreadsRegion {
public:
AllowThreadsRegion() { allowThreads(); }
~AllowThreadsRegion() { endAllowThreads(); }
};
} // namespace threading
} // namespace pyston
#endif
...@@ -15,14 +15,12 @@ ...@@ -15,14 +15,12 @@
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include <cmath> #include <cmath>
#include "codegen/compvars.h"
#include "core/types.h" #include "core/types.h"
#include "runtime/gc_runtime.h" #include "runtime/gc_runtime.h"
#include "runtime/inline/boxing.h"
#include "runtime/types.h" #include "runtime/types.h"
#include "runtime/util.h" #include "runtime/util.h"
#include "runtime/inline/boxing.h"
#include "codegen/compvars.h"
namespace pyston { namespace pyston {
......
// Copyright (c) 2014 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <pthread.h>
#include <stddef.h>
#include "codegen/compvars.h"
#include "core/threading.h"
#include "core/types.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
using namespace pyston::threading;
namespace pyston {
static_assert(sizeof(pthread_t) <= sizeof(BoxedInt::n), "");
BoxedModule* thread_module;
static void* thread_start(void* _args) {
std::vector<Box*>* args = static_cast<std::vector<Box*>*>(_args);
assert(args->size() == 2 || args->size() == 3);
Box* target = (*args)[0];
Box* varargs = (*args)[1];
Box* kwargs = NULL;
if (args->size() > 2)
kwargs = (*args)[2];
delete args;
try {
runtimeCall(target, ArgPassSpec(0, 0, true, kwargs != NULL), varargs, kwargs, NULL, NULL, NULL);
} catch (Box* b) {
std::string msg = formatException(b);
printLastTraceback();
fprintf(stderr, "%s\n", msg.c_str());
}
return NULL;
}
// TODO this should take kwargs, which defaults to empty
Box* startNewThread(Box* target, Box* args) {
pthread_t thread_id;
int code = pthread_create(&thread_id, NULL, &thread_start, new std::vector<Box*>({ target, args }));
assert(code == 0);
return boxInt(thread_id ^ 0x12345678901L);
}
void setupThread() {
thread_module = createModule("thread", "__builtin__");
thread_module->giveAttr("start_new_thread", new BoxedFunction(boxRTFunction((void*)startNewThread, BOXED_INT, 2)));
}
}
...@@ -12,12 +12,14 @@ ...@@ -12,12 +12,14 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <cmath>
#include <ctime> #include <ctime>
#include <sys/time.h> #include <sys/time.h>
#include "codegen/compvars.h" #include "codegen/compvars.h"
#include "core/types.h" #include "core/types.h"
#include "runtime/gc_runtime.h" #include "runtime/gc_runtime.h"
#include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
namespace pyston { namespace pyston {
...@@ -31,9 +33,32 @@ Box* timeTime() { ...@@ -31,9 +33,32 @@ Box* timeTime() {
return boxFloat(t); return boxFloat(t);
} }
Box* timeSleep(Box* arg) {
double secs;
if (arg->cls == int_cls)
secs = static_cast<BoxedInt*>(arg)->n;
else if (arg->cls == float_cls)
secs = static_cast<BoxedFloat*>(arg)->d;
else {
raiseExcHelper(TypeError, "a float is required");
}
double fullsecs;
double nanosecs = modf(secs, &fullsecs);
struct timespec req;
req.tv_sec = (int)(fullsecs + 0.01);
req.tv_nsec = (int)(nanosecs * 1000000000);
int code = nanosleep(&req, NULL);
ASSERT(code == 0, "%d", code);
return None;
}
void setupTime() { void setupTime() {
time_module = createModule("time", "__builtin__"); time_module = createModule("time", "__builtin__");
time_module->giveAttr("time", new BoxedFunction(boxRTFunction((void*)timeTime, BOXED_FLOAT, 0))); time_module->giveAttr("time", new BoxedFunction(boxRTFunction((void*)timeTime, BOXED_FLOAT, 0)));
time_module->giveAttr("sleep", new BoxedFunction(boxRTFunction((void*)timeSleep, NONE, 1)));
} }
} }
...@@ -1223,10 +1223,6 @@ extern "C" void dump(void* p) { ...@@ -1223,10 +1223,6 @@ extern "C" void dump(void* p) {
extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope scope, CallRewriteArgs* rewrite_args, extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope scope, CallRewriteArgs* rewrite_args,
ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<const std::string*>* keyword_names) { const std::vector<const std::string*>* keyword_names) {
RELEASE_ASSERT(!argspec.has_starargs, "");
RELEASE_ASSERT(!argspec.has_kwargs, "");
RELEASE_ASSERT(argspec.num_keywords == 0, "");
int npassed_args = argspec.totalPassed(); int npassed_args = argspec.totalPassed();
if (rewrite_args) { if (rewrite_args) {
...@@ -1519,10 +1515,6 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -1519,10 +1515,6 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
extern "C" Box* callattr(Box* obj, std::string* attr, bool clsonly, ArgPassSpec argspec, Box* arg1, Box* arg2, extern "C" Box* callattr(Box* obj, std::string* attr, bool clsonly, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names) { Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names) {
RELEASE_ASSERT(!argspec.has_starargs, "");
RELEASE_ASSERT(!argspec.has_kwargs, "");
RELEASE_ASSERT(argspec.num_keywords == 0, "");
int npassed_args = argspec.totalPassed(); int npassed_args = argspec.totalPassed();
static StatCounter slowpath_callattr("slowpath_callattr"); static StatCounter slowpath_callattr("slowpath_callattr");
...@@ -1752,7 +1744,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -1752,7 +1744,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
const std::vector<AST_expr*>* arg_names = f->getArgNames(); const std::vector<AST_expr*>* arg_names = f->getArgNames();
if (arg_names == nullptr && argspec.num_keywords) { if (arg_names == nullptr && argspec.num_keywords) {
raiseExcHelper(TypeError, "<function>() doesn't take keyword arguments"); raiseExcHelper(TypeError, "<function @%p>() doesn't take keyword arguments", f->versions[0]->code);
} }
if (argspec.num_keywords) if (argspec.num_keywords)
...@@ -2556,10 +2548,6 @@ static void assertInitNone(Box* obj) { ...@@ -2556,10 +2548,6 @@ static void assertInitNone(Box* obj) {
Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names) { Box* arg3, Box** args, const std::vector<const std::string*>* keyword_names) {
RELEASE_ASSERT(!argspec.has_starargs, "");
RELEASE_ASSERT(!argspec.has_kwargs, "");
RELEASE_ASSERT(argspec.num_keywords == 0, "");
int npassed_args = argspec.totalPassed(); int npassed_args = argspec.totalPassed();
static StatCounter slowpath_typecall("slowpath_typecall"); static StatCounter slowpath_typecall("slowpath_typecall");
...@@ -2632,6 +2620,15 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp ...@@ -2632,6 +2620,15 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
Box* made; Box* made;
RewriterVar r_made; RewriterVar r_made;
auto new_argspec = argspec;
if (npassed_args > 1 && new_attr == typeLookup(object_cls, _new_str, NULL, NULL)) {
if (init_attr == typeLookup(object_cls, _init_str, NULL, NULL)) {
raiseExcHelper(TypeError, "object.__new__() takes no parameters");
} else {
new_argspec = ArgPassSpec(1);
}
}
if (rewrite_args) { if (rewrite_args) {
if (init_attr) if (init_attr)
r_init.push(); r_init.push();
...@@ -2658,18 +2655,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp ...@@ -2658,18 +2655,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
r_new.push(); r_new.push();
auto new_argspec = argspec; made = runtimeCallInternal(new_attr, &srewrite_args, new_argspec, cls, arg2, arg3, args, keyword_names);
auto new_keyword_names = keyword_names;
if (npassed_args > 1 && new_attr == typeLookup(object_cls, _new_str, NULL, NULL)) {
if (init_attr == typeLookup(object_cls, _init_str, NULL, NULL)) {
raiseExcHelper(TypeError, "object.__new__() takes no parameters");
} else {
new_argspec = ArgPassSpec(1);
new_keyword_names = NULL;
}
}
made = runtimeCallInternal(new_attr, &srewrite_args, new_argspec, cls, arg2, arg3, args, new_keyword_names);
if (!srewrite_args.out_success) if (!srewrite_args.out_success)
rewrite_args = NULL; rewrite_args = NULL;
...@@ -2691,12 +2677,12 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp ...@@ -2691,12 +2677,12 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
r_init = rewrite_args->rewriter->pop(-2); r_init = rewrite_args->rewriter->pop(-2);
} }
} else { } else {
made = runtimeCallInternal(new_attr, NULL, argspec, cls, arg2, arg3, args, keyword_names); made = runtimeCallInternal(new_attr, NULL, new_argspec, cls, arg2, arg3, args, keyword_names);
} }
assert(made); assert(made);
// If this is true, not supposed to call __init__: // If this is true, not supposed to call __init__:
assert(made->cls == ccls && "allowed but unsupported"); RELEASE_ASSERT(made->cls == ccls, "allowed but unsupported");
if (init_attr) { if (init_attr) {
Box* initrtn; Box* initrtn;
......
...@@ -557,9 +557,10 @@ void setupRuntime() { ...@@ -557,9 +557,10 @@ void setupRuntime() {
// being tracked in sys.modules: // being tracked in sys.modules:
setupSys(); setupSys();
setupBuiltins();
setupMath(); setupMath();
setupTime(); setupTime();
setupBuiltins(); setupThread();
setupCAPI(); setupCAPI();
......
...@@ -51,9 +51,10 @@ void setupCAPI(); ...@@ -51,9 +51,10 @@ void setupCAPI();
void teardownCAPI(); void teardownCAPI();
void setupSys(); void setupSys();
void setupBuiltins();
void setupMath(); void setupMath();
void setupTime(); void setupTime();
void setupBuiltins(); void setupThread();
BoxedDict* getSysModulesDict(); BoxedDict* getSysModulesDict();
BoxedList* getSysPath(); BoxedList* getSysPath();
...@@ -72,7 +73,7 @@ extern "C" { ...@@ -72,7 +73,7 @@ extern "C" {
extern Box* repr_obj, *len_obj, *hash_obj, *range_obj, *abs_obj, *min_obj, *max_obj, *open_obj, *chr_obj, *ord_obj, extern Box* repr_obj, *len_obj, *hash_obj, *range_obj, *abs_obj, *min_obj, *max_obj, *open_obj, *chr_obj, *ord_obj,
*trap_obj; *trap_obj;
} // these are only needed for functionRepr, which is hacky } // these are only needed for functionRepr, which is hacky
extern "C" { extern BoxedModule* sys_module, *math_module, *time_module, *builtins_module; } extern "C" { extern BoxedModule* sys_module, *builtins_module, *math_module, *time_module, *thread_module; }
extern "C" Box* boxBool(bool); extern "C" Box* boxBool(bool);
extern "C" Box* boxInt(i64); extern "C" Box* boxInt(i64);
......
# skip-if: True
# - Pyston is not yet thread safe. this test sometimes works and sometimes doesn't.
# - threads also seem to cause much greater memory usage for both CPython and Pyston and
# blow out the memory limits set by the tester.
from thread import start_new_thread
import time
done = 0
def run(arg):
global done
print "in other thread!", arg
done = 1
print "starting!"
t = start_new_thread(run, (5,))
print type(t)
while not done:
time.sleep(0)
print "done!"
...@@ -118,7 +118,12 @@ def run_test(fn, check_stats, run_memcheck): ...@@ -118,7 +118,12 @@ def run_test(fn, check_stats, run_memcheck):
l = l[len("# run_args:"):].split() l = l[len("# run_args:"):].split()
jit_args += l jit_args += l
elif l.startswith("# expected:"): elif l.startswith("# expected:"):
expected = l[len("# run_args:"):].strip() expected = l[len("# expected:"):].strip()
elif l.startswith("# skip-if:"):
skip_if = l[len("# skip-if:"):].strip()
skip = eval(skip_if)
if skip:
return r + " (skipped due to 'skip-if: %s')" % skip_if[:30]
assert expected in ("success", "fail", "statfail"), expected assert expected in ("success", "fail", "statfail"), expected
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment