|
|
@ -1,5 +1,6 @@ |
|
|
|
#include "erl_nif.h"
|
|
|
|
#include <atomic>
|
|
|
|
#include <set>
|
|
|
|
using namespace std; |
|
|
|
|
|
|
|
const int LockSize = 2097152; |
|
|
@ -10,20 +11,6 @@ ERL_NIF_TERM atomTrue; |
|
|
|
ERL_NIF_TERM atomFalse; |
|
|
|
ERL_NIF_TERM atomUndefined; |
|
|
|
|
|
|
|
typedef struct KeyNode_r{ |
|
|
|
int KeyIx; |
|
|
|
struct KeyNode_r *next; |
|
|
|
} KeyNode; |
|
|
|
|
|
|
|
bool isNotCurLocked(KeyNode *LockedHead, int KeyIx){ |
|
|
|
KeyNode *temp = LockedHead; |
|
|
|
while (temp != NULL){ |
|
|
|
if (temp->KeyIx == KeyIx) return false; |
|
|
|
temp = temp->next; |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
int nifLoad(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM){ |
|
|
|
atomTrue = enif_make_atom(env, "true"); |
|
|
|
atomFalse = enif_make_atom(env, "false"); |
|
|
@ -50,80 +37,79 @@ bool lockOne(ErlNifEnv *env, ErlNifPid *ThePid, int KeyIx, uint64_t Val){ |
|
|
|
} |
|
|
|
|
|
|
|
ERL_NIF_TERM tryLock(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]){ |
|
|
|
if (enif_is_list(env, argv[0])){ |
|
|
|
ERL_NIF_TERM allList = argv[0]; |
|
|
|
ERL_NIF_TERM head; |
|
|
|
ErlNifPid ThePid; |
|
|
|
enif_self(env, &ThePid); |
|
|
|
uint64_t Val = (uint64_t)(ThePid.pid); |
|
|
|
int KeyIx; |
|
|
|
KeyNode *LockedHead = NULL; |
|
|
|
while (enif_get_list_cell(env, allList, &head, &allList)){ |
|
|
|
KeyIx = enif_hash(ERL_NIF_INTERNAL_HASH, head, HashSalt) % LockSize; |
|
|
|
KeyNode OneKeyNode = {KeyIx, LockedHead}; |
|
|
|
if (isNotCurLocked(LockedHead, KeyIx)){ |
|
|
|
if (lockOne(env, &ThePid, KeyIx, Val)){ |
|
|
|
LockedHead = &OneKeyNode; |
|
|
|
}else{ |
|
|
|
uint64_t RExpected; |
|
|
|
KeyNode *temp = LockedHead; |
|
|
|
while (temp != NULL){ |
|
|
|
RExpected = Val; |
|
|
|
LockSlot[temp->KeyIx].compare_exchange_strong(RExpected, 0); |
|
|
|
temp = temp->next; |
|
|
|
} |
|
|
|
return atomFalse; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
int KeyIx; |
|
|
|
enif_get_int(env, argv[0], &KeyIx); |
|
|
|
ErlNifPid ThePid; |
|
|
|
enif_self(env, &ThePid); |
|
|
|
uint64_t Val = (uint64_t)(ThePid.pid); |
|
|
|
|
|
|
|
if (lockOne(env, &ThePid, KeyIx, Val)){ |
|
|
|
return atomTrue; |
|
|
|
}else{ |
|
|
|
int KeyIx; |
|
|
|
KeyIx = enif_hash(ERL_NIF_INTERNAL_HASH, argv[0], HashSalt) % LockSize; |
|
|
|
ErlNifPid ThePid; |
|
|
|
enif_self(env, &ThePid); |
|
|
|
uint64_t Val = (uint64_t)(ThePid.pid); |
|
|
|
|
|
|
|
if (lockOne(env, &ThePid, KeyIx, Val)){ |
|
|
|
return atomTrue; |
|
|
|
return atomFalse; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
ERL_NIF_TERM tryLocks(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]){ |
|
|
|
ERL_NIF_TERM allList = argv[0]; |
|
|
|
ERL_NIF_TERM head; |
|
|
|
ErlNifPid ThePid; |
|
|
|
enif_self(env, &ThePid); |
|
|
|
uint64_t Val = (uint64_t)(ThePid.pid); |
|
|
|
int KeyIx; |
|
|
|
int cnt = -1; |
|
|
|
|
|
|
|
while (enif_get_list_cell(env, allList, &head, &allList)){ |
|
|
|
enif_get_int(env, head, &KeyIx); |
|
|
|
if(lockOne(env, &ThePid, KeyIx, Val)){ |
|
|
|
cnt++; |
|
|
|
}else{ |
|
|
|
uint64_t RExpected; |
|
|
|
allList = argv[0]; |
|
|
|
for(int i = 0; i <= cnt; i++){ |
|
|
|
enif_get_list_cell(env, allList, &head, &allList); |
|
|
|
enif_get_int(env, head, &KeyIx); |
|
|
|
RExpected = Val; |
|
|
|
LockSlot[KeyIx].compare_exchange_strong(RExpected, 0); |
|
|
|
} |
|
|
|
return atomFalse; |
|
|
|
} |
|
|
|
} |
|
|
|
return atomTrue; |
|
|
|
} |
|
|
|
|
|
|
|
ERL_NIF_TERM releaseLock(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]){ |
|
|
|
if (enif_is_list(env, argv[0])){ |
|
|
|
ERL_NIF_TERM allList = argv[0]; |
|
|
|
ERL_NIF_TERM head; |
|
|
|
ErlNifPid ThePid; |
|
|
|
enif_self(env, &ThePid); |
|
|
|
uint64_t Expected = (uint64_t)(ThePid.pid); |
|
|
|
uint64_t RExpected; |
|
|
|
int KeyIx; |
|
|
|
int isAllOk = 1; |
|
|
|
|
|
|
|
while (enif_get_list_cell(env, allList, &head, &allList)){ |
|
|
|
KeyIx = enif_hash(ERL_NIF_INTERNAL_HASH, head, HashSalt) % LockSize; |
|
|
|
RExpected = Expected; |
|
|
|
if (!LockSlot[KeyIx].compare_exchange_strong(RExpected, 0)){ |
|
|
|
isAllOk = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
return isAllOk > 0 ? atomTrue : atomFalse; |
|
|
|
int KeyIx; |
|
|
|
enif_get_int(env, argv[0], &KeyIx); |
|
|
|
ErlNifPid ThePid; |
|
|
|
enif_self(env, &ThePid); |
|
|
|
uint64_t Expected = (uint64_t)(ThePid.pid); |
|
|
|
|
|
|
|
if (LockSlot[KeyIx].compare_exchange_strong(Expected, 0)){ |
|
|
|
return atomTrue; |
|
|
|
}else{ |
|
|
|
int KeyIx; |
|
|
|
KeyIx = enif_hash(ERL_NIF_INTERNAL_HASH, argv[0], HashSalt) % LockSize; |
|
|
|
ErlNifPid ThePid; |
|
|
|
enif_self(env, &ThePid); |
|
|
|
uint64_t Expected = (uint64_t)(ThePid.pid); |
|
|
|
|
|
|
|
if (LockSlot[KeyIx].compare_exchange_strong(Expected, 0)){ |
|
|
|
return atomTrue; |
|
|
|
}else{ |
|
|
|
return atomFalse; |
|
|
|
return atomFalse; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
ERL_NIF_TERM releaseLocks(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]){ |
|
|
|
ERL_NIF_TERM allList = argv[0]; |
|
|
|
ERL_NIF_TERM head; |
|
|
|
ErlNifPid ThePid; |
|
|
|
enif_self(env, &ThePid); |
|
|
|
uint64_t Expected = (uint64_t)(ThePid.pid); |
|
|
|
uint64_t RExpected; |
|
|
|
int KeyIx; |
|
|
|
int isAllOk = 1; |
|
|
|
|
|
|
|
while (enif_get_list_cell(env, allList, &head, &allList)){ |
|
|
|
enif_get_int(env, head, &KeyIx); |
|
|
|
RExpected = Expected; |
|
|
|
if (!LockSlot[KeyIx].compare_exchange_strong(RExpected, 0)){ |
|
|
|
isAllOk = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
return isAllOk > 0 ? atomTrue : atomFalse; |
|
|
|
} |
|
|
|
|
|
|
|
ERL_NIF_TERM getLockPid(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]){ |
|
|
@ -142,7 +128,9 @@ ERL_NIF_TERM getLockPid(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]){ |
|
|
|
|
|
|
|
static ErlNifFunc nifFuncs[] = { |
|
|
|
{"tryLock", 1, tryLock}, |
|
|
|
{"tryLocks", 1, tryLocks}, |
|
|
|
{"releaseLock", 1, releaseLock}, |
|
|
|
{"releaseLocks", 1, releaseLocks}, |
|
|
|
{"getLockPid", 1, getLockPid} |
|
|
|
}; |
|
|
|
|