Commit fef27673 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Implement more of thread.lock

parent df8ee5c6
......@@ -45,6 +45,22 @@ Box* startNewThread(Box* target, Box* args) {
return boxInt(thread_id ^ 0x12345678901L);
}
#define CHECK_STATUS(name) \
if (status != 0) { \
perror(name); \
error = 1; \
}
/*
* As of February 2002, Cygwin thread implementations mistakenly report error
* codes in the return value of the sem_ calls (like the pthread_ functions).
* Correct implementations return -1 and put the code in errno. This supports
* either.
*/
static int fix_status(int status) {
return (status == -1) ? errno : status;
}
static BoxedClass* thread_lock_cls;
class BoxedThreadLock : public Box {
private:
......@@ -55,12 +71,38 @@ public:
DEFAULT_CLASS(thread_lock_cls);
static Box* acquire(Box* _self) {
static Box* acquire(Box* _self, Box* _waitflag) {
RELEASE_ASSERT(_self->cls == thread_lock_cls, "");
BoxedThreadLock* self = static_cast<BoxedThreadLock*>(_self);
pthread_mutex_lock(&self->lock);
return None;
RELEASE_ASSERT(_waitflag->cls == int_cls, "");
int waitflag = static_cast<BoxedInt*>(_waitflag)->n;
// Copied + adapted from CPython:
int success;
auto thelock = &self->lock;
int status, error = 0;
{
threading::GLAllowThreadsReadRegion _allow_threads;
do {
if (waitflag)
status = fix_status(pthread_mutex_lock(thelock));
else
status = fix_status(pthread_mutex_trylock(thelock));
} while (status == EINTR); /* Retry if interrupted by a signal */
}
if (waitflag) {
CHECK_STATUS("mutex_lock");
} else if (status != EBUSY) {
CHECK_STATUS("mutex_trylock");
}
success = (status == 0) ? 1 : 0;
return boxBool(status == 0);
}
static Box* release(Box* _self) {
......@@ -70,32 +112,57 @@ public:
pthread_mutex_unlock(&self->lock);
return None;
}
static Box* exit(Box* _self, Box* arg1, Box* arg2, Box** args) { return release(_self); }
};
Box* allocateLock() {
return new BoxedThreadLock();
}
static BoxedClass* thread_local_cls;
class BoxedThreadLocal : public Box {
public:
BoxedThreadLocal() {}
DEFAULT_CLASS(thread_local_cls);
};
Box* getIdent() {
return boxInt(pthread_self());
}
Box* stackSize() {
Py_FatalError("unimplemented");
}
void setupThread() {
thread_module = createModule("thread", "__builtin__");
thread_module->giveAttr("start_new_thread", new BoxedFunction(boxRTFunction((void*)startNewThread, BOXED_INT, 2)));
thread_module->giveAttr("allocate_lock", new BoxedFunction(boxRTFunction((void*)allocateLock, UNKNOWN, 0)));
thread_module->giveAttr("get_ident", new BoxedFunction(boxRTFunction((void*)getIdent, BOXED_INT, 0)));
thread_module->giveAttr("stack_size", new BoxedFunction(boxRTFunction((void*)stackSize, BOXED_INT, 0)));
thread_lock_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedThreadLock), false);
thread_lock_cls->giveAttr("__name__", boxStrConstant("lock"));
thread_lock_cls->giveAttr("__module__", boxStrConstant("thread"));
thread_lock_cls->giveAttr("acquire", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::acquire, NONE, 1)));
thread_lock_cls->giveAttr(
"acquire",
new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::acquire, NONE, 2, 1, false, false), { boxInt(1) }));
thread_lock_cls->giveAttr("release", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::release, NONE, 1)));
thread_lock_cls->giveAttr("acquire_lock", thread_lock_cls->getattr("acquire"));
thread_lock_cls->giveAttr("release_lock", thread_lock_cls->getattr("release"));
thread_lock_cls->giveAttr("__enter__", thread_lock_cls->getattr("acquire"));
thread_lock_cls->giveAttr("__exit__", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::exit, NONE, 4)));
thread_lock_cls->freeze();
thread_local_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedThreadLocal), false);
thread_local_cls->giveAttr("__name__", boxStrConstant("_local"));
thread_local_cls->giveAttr("__module__", boxStrConstant("thread"));
thread_local_cls->freeze();
thread_module->giveAttr("_local", thread_local_cls);
BoxedClass* ThreadError
= new BoxedHeapClass(Exception, NULL, Exception->attrs_offset, Exception->tp_basicsize, false);
ThreadError->giveAttr("__name__", boxStrConstant("error"));
......
......@@ -19,3 +19,30 @@ while not done:
print "done!"
l = allocate_lock()
print l.acquire()
print l.acquire(0)
print l.release()
print l.acquire(0)
lock = allocate_lock()
state = 0
def run2():
global state
print lock.acquire(0)
state = 1
print lock.acquire()
lock.release()
state = 2
with lock:
start_new_thread(run2, ())
while state != 1:
time.sleep(0)
while state != 2:
time.sleep(0)
print "done!"
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