Skip to content

Add top-level mutex class #3739

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 6 commits 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/actors4.d
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,7 @@ tostringfun(e:Expr):Expr := (
Ccode(void, "sprintf((char *)", buf, "->array, \"%d\", ", load(x.v), ")");
Ccode(void, buf, "->len = strlen((char *)", buf, "->array)");
toExpr(buf))
is x:mutexCell do toExpr("<<a mutex>>")
);
setupfun("simpleToString",tostringfun);

Expand Down
1 change: 1 addition & 0 deletions M2/Macaulay2/d/basic.d
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export hash(e:Expr):hash_t := (
-- cast to long first to avoid "different size" compiler warning
is x:pointerCell do Ccode(hash_t, "(long)", x.v)
is x:atomicIntCell do x.hash
is x:mutexCell do x.hash
);

export hash(x:List):hash_t := (
Expand Down
2 changes: 2 additions & 0 deletions M2/Macaulay2/d/classes.dd
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ setupconst("Task",Expr(taskClass));
setupconst("FileOutputSyncState",Expr(fileOutputSyncStateClass));
setupconst("Pointer",Expr(pointerClass));
setupconst("AtomicInt",Expr(atomicIntClass));
setupconst("Mutex",Expr(mutexClass));

export ancestor(o:HashTable,p:HashTable):bool := (
while true do (
Expand Down Expand Up @@ -175,6 +176,7 @@ export Class(e:Expr):HashTable := (
is fileOutputSyncState do fileOutputSyncStateClass
is pointerCell do pointerClass
is atomicIntCell do atomicIntClass
is mutexCell do mutexClass
);
classfun(e:Expr):Expr := Expr(Class(e));
-- # typical value: class, Thing, Type
Expand Down
4 changes: 4 additions & 0 deletions M2/Macaulay2/d/equality.dd
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ export equal(lhs:Expr,rhs:Expr):Expr := (
when rhs
is y:atomicIntCell do if x == y then True else False
else False)
is x:mutexCell do (
when rhs
is y:mutexCell do if x == y then True else False
else False)
);

-- Local Variables:
Expand Down
1 change: 1 addition & 0 deletions M2/Macaulay2/d/expr.d
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ export RRiClass := newbignumbertype();
export pointerClass := newbasictype();
export atomicIntClass := newbasictype();
export pseudocodeClosureClass := newtypeof(pseudocodeClass);
export mutexClass := newbasictype();
-- all new types, dictionaries, and classes go just above this line, if possible, so hash codes don't change gratuitously!


Expand Down
4 changes: 3 additions & 1 deletion M2/Macaulay2/d/parse.d
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ export TaskCell := {+ body:TaskCellBody };
export pointerCell := {+ v:voidPointer };

export atomicIntCell := {+ v:atomicField, hash:hash_t };
export mutexCell := {+ v:ThreadMutex, hash:hash_t };

export Expr := (
CCcell or
Expand Down Expand Up @@ -414,7 +415,8 @@ export Expr := (
TaskCell or
fileOutputSyncState or
pointerCell or
atomicIntCell
atomicIntCell or
mutexCell
);

--Unique True expression
Expand Down
48 changes: 48 additions & 0 deletions M2/Macaulay2/d/pthread.d
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,54 @@ export getIOThreadMode(e:Expr):Expr := (
else WrongArg("a file or ()"));
setupfun("getIOThreadMode", getIOThreadMode);

WrongArgMutex():Expr := WrongArg("a mutex");

mutexFinalizer(obj:voidPointer, data:voidPointer):void := (
mutex := Ccode(ThreadMutex, "*(pthread_mutex_t *)", obj);
destroy(mutex););

mutexInit(e:Expr):Expr := (
when e
is HashTable do (
ptr := GCmalloc(Pointer "pthread_mutex_t *");
mutex := Ccode(ThreadMutex, "*", ptr);
r := init(mutex);
if r != 0 then return buildErrorPacketErrno("pthread_mutex_init", r);
Ccode(void, "GC_REGISTER_FINALIZER(", ptr, ", ",
"(GC_finalization_proc)", mutexFinalizer, ", NULL, NULL, NULL)");
cell := mutexCell(mutex, hash_t(0));
cell.hash = hashFromAddress(Expr(cell));
Expr(cell))
else WrongArgHashTable());
installMethod(NewS, mutexClass, mutexInit);

lock(e:Expr):Expr := (
when e
is m:mutexCell do (
r := lock(m.v);
if r == 0 then nullE
else buildErrorPacketErrno("pthread_mutex_lock", r))
else WrongArgMutex());
setupfun("lock0", lock);

trylock(e:Expr):Expr := (
when e
is m:mutexCell do (
r := trylock(m.v);
if r == 0 then nullE
else buildErrorPacketErrno("pthread_mutex_trylock", r))
else WrongArgMutex());
setupfun("tryLock0", trylock);

unlock(e:Expr):Expr := (
when e
is m:mutexCell do (
r := unlock(m.v);
if r == 0 then nullE
else buildErrorPacketErrno("pthread_mutex_unlock", r))
else WrongArgMutex());
setupfun("unlock0", unlock);

-- 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
4 changes: 4 additions & 0 deletions M2/Macaulay2/m2/exports.m2
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ export {
"MutableHashTable",
"MutableList",
"MutableMatrix",
"Mutex",
"midpoint",
"NCLex",
"Name",
Expand Down Expand Up @@ -890,6 +891,7 @@ export {
"local",
"localDictionaries",
"locate",
"lock",
"log",
"log1p",
"lookup",
Expand Down Expand Up @@ -1228,6 +1230,7 @@ export {
"truncate",
"truncateOutput",
"try",
"tryLock",
"tutorial",
"typicalValues",
"uniquePermutations",
Expand All @@ -1240,6 +1243,7 @@ export {
"uninstallPackage",
"union",
"unique",
"unlock",
"unsequence",
"unstack",
"urlEncode",
Expand Down
18 changes: 0 additions & 18 deletions M2/Macaulay2/m2/integers.m2
Original file line number Diff line number Diff line change
Expand Up @@ -105,24 +105,6 @@ changeBase(String, ZZ) := ZZ => changeBase0
changeBase(String, ZZ, ZZ) := String => (s, oldbase, newbase) -> (
changeBase(changeBase(s, oldbase), newbase))

-----------------------------------------------------------------------------
-- AtomicInt
-----------------------------------------------------------------------------

AtomicInt.synonym = "atomic integer"

scan({symbol +=, symbol -=, symbol &=, symbol |=, symbol ^^=},
op -> typicalValues#(op, AtomicInt) = ZZ)

store = method()
store(AtomicInt, ZZ) := atomicStore

exchange = method()
exchange(AtomicInt, ZZ) := atomicExchange

compareExchange = method()
compareExchange(AtomicInt, ZZ, ZZ) := atomicCompareExchange

-- Local Variables:
-- compile-command: "make -C $M2BUILDDIR/Macaulay2/m2 "
-- End:
19 changes: 0 additions & 19 deletions M2/Macaulay2/m2/lists.m2
Original file line number Diff line number Diff line change
Expand Up @@ -320,25 +320,6 @@ pack(ZZ, BasicList) := List => pack'
pack(String, ZZ) :=
pack(BasicList, ZZ) := List => (L, n) -> pack'(n, L)

-----------------------------------------------------------------------------

parallelApplyRaw = (L, f) ->
-- 'reverse's to minimize thread switching in 'taskResult's:
reverse (taskResult \ reverse apply(L, e -> schedule(f, e)));
parallelApply = method(Options => {Strategy => null})
parallelApply(BasicList, Function) := o -> (L, f) -> (
if o.Strategy === "raw" then return parallelApplyRaw(L, f);
n := #L;
numThreads := min(n + 1, maxAllowableThreads);
oldAllowableThreads := allowableThreads;
if allowableThreads < numThreads then allowableThreads = numThreads;
numChunks := 3 * numThreads;
res := if n <= numChunks then toList parallelApplyRaw(L, f) else
flatten parallelApplyRaw(pack(L, ceiling(n / numChunks)), chunk -> apply(chunk, f));
allowableThreads = oldAllowableThreads;
res);


-- Local Variables:
-- compile-command: "make -C $M2BUILDDIR/Macaulay2/m2 "
-- End:
1 change: 1 addition & 0 deletions M2/Macaulay2/m2/loadsequence
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ shared.m2
autoload.m2
system.m2
regex.m2
threads.m2

profile.m2
debugging.m2
Expand Down
55 changes: 55 additions & 0 deletions M2/Macaulay2/m2/threads.m2
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
-----------------------------------------------------------------------------
-- AtomicInt
-----------------------------------------------------------------------------

AtomicInt.synonym = "atomic integer"

scan({symbol +=, symbol -=, symbol &=, symbol |=, symbol ^^=},
op -> typicalValues#(op, AtomicInt) = ZZ)

store = method()
store(AtomicInt, ZZ) := atomicStore

exchange = method()
exchange(AtomicInt, ZZ) := atomicExchange

compareExchange = method()
compareExchange(AtomicInt, ZZ, ZZ) := atomicCompareExchange

-----------------------------------------------------------------------------
-- Mutex
-----------------------------------------------------------------------------

Mutex.synonym = "mutex"
globalAssignment Mutex
net Mutex := x -> toString (
if hasAttribute(x, ReverseDictionary)
then getAttribute(x, ReverseDictionary)
else x)

lock = method()
lock Mutex := lock0

tryLock = method()
tryLock Mutex := tryLock0

unlock = method()
unlock Mutex := unlock0

-----------------------------------------------------------------------------

parallelApplyRaw = (L, f) ->
-- 'reverse's to minimize thread switching in 'taskResult's:
reverse (taskResult \ reverse apply(L, e -> schedule(f, e)));
parallelApply = method(Options => {Strategy => null})
parallelApply(BasicList, Function) := o -> (L, f) -> (
if o.Strategy === "raw" then return parallelApplyRaw(L, f);
n := #L;
numThreads := min(n + 1, maxAllowableThreads);
oldAllowableThreads := allowableThreads;
if allowableThreads < numThreads then allowableThreads = numThreads;
numChunks := 3 * numThreads;
res := if n <= numChunks then toList parallelApplyRaw(L, f) else
flatten parallelApplyRaw(pack(L, ceiling(n / numChunks)), chunk -> apply(chunk, f));
allowableThreads = oldAllowableThreads;
res);
1 change: 1 addition & 0 deletions M2/Macaulay2/packages/Macaulay2Doc/doc_atomic.m2
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ doc ///
between $-2^{31}$ and $2^{31} - 1$.
SeeAlso
"parallel programming with threads and tasks"
Mutex
Subnodes
(NewFromMethod, AtomicInt, ZZ)
(NewFromMethod, ZZ, AtomicInt)
Expand Down
Loading
Loading