Skip to content

Add threadLock keyword -- locks mutex, evals code, then unlocks #3749

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: development
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions M2/Macaulay2/d/binding.d
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ bumpPrecedence();
export breakpointS := special("breakpoint", unaryop, precSpace, wide);
export profileS := special("profile", unaryop, precSpace, wide);
export shieldS := special("shield", unaryop, precSpace, wide);
export threadLockS := special("threadLock", unaryop, precSpace, wide);
export throwS := special("throw", nunaryop, precSpace, wide);
export returnS := special("return", nunaryop, precSpace, wide);
export breakS := special("break", nunaryop, precSpace, wide);
Expand Down
15 changes: 15 additions & 0 deletions M2/Macaulay2/d/pthread.d
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use evaluate;
use expr;

header "#include \"../system/supervisorinterface.h\"";
header "#include <errno.h>"; -- for EBUSY


taskCreatePush(f:function(TaskCellBody):null,tb:TaskCellBody) ::= Ccode(taskPointer,
Expand Down Expand Up @@ -231,6 +232,20 @@ export getIOThreadMode(e:Expr):Expr := (
else WrongArg("a file or ()"));
setupfun("getIOThreadMode", getIOThreadMode);

-- TODO: what if we cancel a task before it unlocks the mutex?
mutex := newMutex;
threadLock(c:Code):Expr := (
r := 0;
while (r = trylock(mutex); r == Ccode(int, "EBUSY")) do (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not good. I think you want pthread_cond_wait or similar.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I've read, pthread_mutex_trylock is the only way to check if a mutex is locked. pthread_cond_wait blocks until some condition is met, and we don't want to block since we want to check for interrupts.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely think we need pthread conditions, because you can signal only one or all threads using pthread_cond_signal and pthread_cond_broadcast that an event has changed. This is how tasks are implemented too. e.g. this is how taskResult blocks:

lock_guard<pthreadMutex> lock(m_Mutex);
while(!m_Done && m_KeepRunning)
{
pthread_cond_wait(&m_FinishCondition,&m_Mutex.m_Mutex);
}
return m_Result;

In fact, I suspect if we change interrupt_handler in main.cpp to also signal the current blocking task, it would interrupt just fine.

f := eval(dummyCode); -- handle interrupts
when f is Error do return f else nothing);
if r == 0 then (
e := eval(c);
unlock(mutex);
e)
else buildErrorPacketErrno("threadLock", r));
setupop(threadLockS, threadLock);

-- Local Variables:
-- compile-command: "echo \"make: Entering directory \\`$M2BUILDDIR/Macaulay2/d'\" && make -C $M2BUILDDIR/Macaulay2/d pthread.o "
-- End:
1 change: 1 addition & 0 deletions M2/Macaulay2/d/pthread0.d
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export SpinLock := atomicType "struct spinlockStructure";
export init(x:ThreadMutex) ::= Ccode(int, "pthread_mutex_init(&(",lvalue(x),"),NULL)");
export destroy(x:ThreadMutex) ::= Ccode(int, "pthread_mutex_destroy(&(",lvalue(x),"))");
export lock(x:ThreadMutex) ::= Ccode(int, "pthread_mutex_lock(&(",lvalue(x),"))");
export trylock(x:ThreadMutex) ::= Ccode(int, "pthread_mutex_trylock(&(",lvalue(x),"))");
export unlock(x:ThreadMutex) ::= Ccode(int, "pthread_mutex_unlock(&(",lvalue(x),"))");
export getthreadself() ::= Ccode(Thread, "pthread_self()");

Expand Down
1 change: 1 addition & 0 deletions M2/Macaulay2/m2/exports.m2
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,7 @@ export {
"texMath",
"then",
"threadLocal",
"threadLock",
"throw",
"time",
"times",
Expand Down
7 changes: 7 additions & 0 deletions M2/Macaulay2/tests/normal/threads.m2
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ assert Equation(getIOThreadMode f, 2)

removeFile fn

-- threadLock
-- mutable lists are *not* thread safe
-- if they ever become thread safe, then change this test
x = new MutableList
taskResult \ apply(1000, i -> schedule(() -> threadLock x##x = null));
assert Equation(#x, 1000)

-- Local Variables:
-- compile-command: "make -C $M2BUILDDIR/Macaulay2/packages/Macaulay2Doc/test threads.out"
-- End:
Loading