Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
d4a204b6
Commit
d4a204b6
authored
Aug 14, 2020
by
Xavier Thompson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Clean up cypclass object lock implementation
parent
b8672147
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
68 additions
and
136 deletions
+68
-136
Cython/Utility/CyObjects.cpp
Cython/Utility/CyObjects.cpp
+68
-136
No files found.
Cython/Utility/CyObjects.cpp
View file @
d4a204b6
...
...
@@ -34,19 +34,20 @@
#include <type_traits>
class
RecursiveUpgradeableRWLock
{
class
CyLock
{
static
pthread_mutex_t
log_guard
;
protected:
pthread_mutex_t
guard
;
pthread_cond_t
wait_readers_depar
t
;
pthread_cond_t
w
ait_writer_depar
t
;
pthread_cond_t
readers_have_lef
t
;
pthread_cond_t
w
riter_has_lef
t
;
atomic
<
pid_t
>
owner_id
;
atomic_int32_t
readers_nb
;
uint32_t
write_count
;
public:
RecursiveUpgradeableRW
Lock
()
{
Cy
Lock
()
{
pthread_mutex_init
(
&
this
->
guard
,
NULL
);
pthread_cond_init
(
&
this
->
wait_readers_depar
t
,
NULL
);
pthread_cond_init
(
&
this
->
w
ait_writer_depar
t
,
NULL
);
pthread_cond_init
(
&
this
->
readers_have_lef
t
,
NULL
);
pthread_cond_init
(
&
this
->
w
riter_has_lef
t
,
NULL
);
this
->
owner_id
=
CyObject_NO_OWNER
;
this
->
readers_nb
=
0
;
this
->
write_count
=
0
;
...
...
@@ -58,14 +59,7 @@
int
tryrlock
();
int
trywlock
();
};
class
LogLock
:
public
RecursiveUpgradeableRWLock
{
static
pthread_mutex_t
log_guard
;
public:
void
wlock
();
void
rlock
();
};
pthread_mutex_t
LogLock
::
log_guard
=
PTHREAD_MUTEX_INITIALIZER
;
pthread_mutex_t
CyLock
::
log_guard
=
PTHREAD_MUTEX_INITIALIZER
;
struct
CyPyObject
{
PyObject_HEAD
...
...
@@ -74,7 +68,7 @@
class
CyObject
:
public
CyPyObject
{
private:
CyObject_ATOMIC_REFCOUNT_TYPE
nogil_ob_refcnt
;
Log
Lock
ob_lock
;
Cy
Lock
ob_lock
;
public:
CyObject
()
:
nogil_ob_refcnt
(
1
)
{}
virtual
~
CyObject
()
{}
...
...
@@ -315,7 +309,7 @@
#endif
/* __cplusplus */
void
RecursiveUpgradeableRW
Lock
::
rlock
()
{
void
Cy
Lock
::
rlock
()
{
pid_t
caller_id
=
syscall
(
SYS_gettid
);
if
(
this
->
owner_id
==
caller_id
)
{
...
...
@@ -325,8 +319,20 @@ void RecursiveUpgradeableRWLock::rlock() {
pthread_mutex_lock
(
&
this
->
guard
);
if
(
this
->
write_count
>
0
)
{
pid_t
owner_id
=
this
->
owner_id
;
pthread_mutex_lock
(
&
(
CyLock
::
log_guard
));
printf
(
"Contention with a writer detected while rlocking lock [%p] in thread #%d:
\n
"
" - lock was already wlocked by thread %d
\n
"
"
\n
"
,
this
,
caller_id
,
owner_id
);
pthread_mutex_unlock
(
&
(
CyLock
::
log_guard
));
}
while
(
this
->
write_count
>
0
)
{
pthread_cond_wait
(
&
this
->
w
ait_writer_depar
t
,
&
this
->
guard
);
pthread_cond_wait
(
&
this
->
w
riter_has_lef
t
,
&
this
->
guard
);
}
this
->
owner_id
=
this
->
readers_nb
++
?
CyObject_MANY_OWNERS
:
caller_id
;
...
...
@@ -334,7 +340,7 @@ void RecursiveUpgradeableRWLock::rlock() {
pthread_mutex_unlock
(
&
this
->
guard
);
}
int
RecursiveUpgradeableRW
Lock
::
tryrlock
()
{
int
Cy
Lock
::
tryrlock
()
{
pid_t
caller_id
=
syscall
(
SYS_gettid
);
if
(
this
->
owner_id
==
caller_id
)
{
...
...
@@ -358,8 +364,7 @@ int RecursiveUpgradeableRWLock::tryrlock() {
return
0
;
}
void
RecursiveUpgradeableRWLock
::
unrlock
()
{
void
CyLock
::
unrlock
()
{
pthread_mutex_lock
(
&
this
->
guard
);
if
(
--
this
->
readers_nb
==
0
)
{
...
...
@@ -368,13 +373,13 @@ void RecursiveUpgradeableRWLock::unrlock() {
}
// broadcast to wake up all the waiting writers
pthread_cond_broadcast
(
&
this
->
wait_readers_depar
t
);
pthread_cond_broadcast
(
&
this
->
readers_have_lef
t
);
}
pthread_mutex_unlock
(
&
this
->
guard
);
}
void
RecursiveUpgradeableRW
Lock
::
wlock
()
{
void
Cy
Lock
::
wlock
()
{
pid_t
caller_id
=
syscall
(
SYS_gettid
);
if
(
this
->
owner_id
==
caller_id
)
{
...
...
@@ -386,26 +391,52 @@ void RecursiveUpgradeableRWLock::wlock() {
pthread_mutex_lock
(
&
this
->
guard
);
if
(
this
->
owner_id
!=
caller_id
)
{
// we wait for readers first and bottleneck the writers after
// this works for a readers preferring approach
pid_t
owner_id
=
this
->
owner_id
;
// because the other way around would require setting write_count to 1 before waiting on the readers
// in order to ensure only one writer at a times goes beyound waiting for the other writers to leave
if
(
owner_id
!=
caller_id
)
{
//
this would be more in line with a writers preferring approach, but that can deadlock when a thread recurses on a readlock
//
this also means that we must broadcast when the readers leave in order to give all the waiting writers a chance to wake up
//
Since we use a reader-preferring approach, we wait first for all readers to leave, and then all writers.
//
The other way around could result in several writers acquiring the lock.
// new readers might still pass before some of the waiting writers, but then they'll just wait some more
// OTOH, if the new readers come, not broadcasting would let some writers wait forever
if
(
this
->
readers_nb
>
0
)
{
if
(
owner_id
==
CyObject_MANY_OWNERS
)
{
pthread_mutex_lock
(
&
(
CyLock
::
log_guard
));
printf
(
"Contention with several other reader threads detected while wlocking lock [%p] in thread #%d:
\n
"
"
\n
"
,
this
,
caller_id
);
pthread_mutex_unlock
(
&
(
CyLock
::
log_guard
));
}
else
{
pthread_mutex_lock
(
&
(
CyLock
::
log_guard
));
printf
(
"Contention with a reader thread detected while wlocking lock [%p] in thread #%d:
\n
"
" - reader thread is %d
\n
"
"
\n
"
,
this
,
caller_id
,
owner_id
);
pthread_mutex_unlock
(
&
(
CyLock
::
log_guard
));
}
}
while
(
this
->
readers_nb
>
0
)
{
pthread_cond_wait
(
&
this
->
wait_readers_depart
,
&
this
->
guard
);
pthread_cond_wait
(
&
this
->
readers_have_left
,
&
this
->
guard
);
}
if
(
this
->
write_count
>
0
)
{
pthread_mutex_lock
(
&
(
CyLock
::
log_guard
));
printf
(
"Contention with another writer detected while wlocking lock [%p] in thread #%d:
\n
"
" - lock was already wlocked by thread %d
\n
"
"
\n
"
,
this
,
caller_id
,
owner_id
);
pthread_mutex_unlock
(
&
(
CyLock
::
log_guard
));
}
while
(
this
->
write_count
>
0
)
{
pthread_cond_wait
(
&
this
->
w
ait_writer_depar
t
,
&
this
->
guard
);
pthread_cond_wait
(
&
this
->
w
riter_has_lef
t
,
&
this
->
guard
);
}
this
->
owner_id
=
caller_id
;
...
...
@@ -416,7 +447,7 @@ void RecursiveUpgradeableRWLock::wlock() {
pthread_mutex_unlock
(
&
this
->
guard
);
}
int
RecursiveUpgradeableRW
Lock
::
trywlock
()
{
int
Cy
Lock
::
trywlock
()
{
pid_t
caller_id
=
syscall
(
SYS_gettid
);
if
(
this
->
owner_id
==
caller_id
)
{
...
...
@@ -450,8 +481,7 @@ int RecursiveUpgradeableRWLock::trywlock() {
return
0
;
}
void
RecursiveUpgradeableRWLock
::
unwlock
()
{
void
CyLock
::
unwlock
()
{
pthread_mutex_lock
(
&
this
->
guard
);
if
(
--
this
->
write_count
==
0
)
{
if
(
this
->
readers_nb
==
0
)
{
...
...
@@ -460,109 +490,11 @@ void RecursiveUpgradeableRWLock::unwlock() {
// broadcast to wake up all the waiting readers, + maybe one waiting writer
// more efficient to count r waiting readers and w waiting writers and signal n + (w > 0) times
pthread_cond_broadcast
(
&
this
->
wait_writer_depart
);
}
pthread_mutex_unlock
(
&
this
->
guard
);
}
void
LogLock
::
rlock
()
{
pid_t
caller_id
=
syscall
(
SYS_gettid
);
if
(
this
->
owner_id
==
caller_id
)
{
++
this
->
readers_nb
;
return
;
}
pthread_mutex_lock
(
&
this
->
guard
);
if
(
this
->
write_count
>
0
)
{
pid_t
owner_id
=
this
->
owner_id
;
pthread_mutex_lock
(
&
(
LogLock
::
log_guard
));
printf
(
"Contention with a writer detected while rlocking lock [%p] in thread #%d:
\n
"
" - lock was already wlocked by thread %d
\n
"
"
\n
"
,
this
,
caller_id
,
owner_id
);
pthread_mutex_unlock
(
&
(
LogLock
::
log_guard
));
pthread_cond_broadcast
(
&
this
->
writer_has_left
);
}
while
(
this
->
write_count
>
0
)
{
pthread_cond_wait
(
&
this
->
wait_writer_depart
,
&
this
->
guard
);
}
this
->
owner_id
=
this
->
readers_nb
++
?
CyObject_MANY_OWNERS
:
caller_id
;
pthread_mutex_unlock
(
&
this
->
guard
);
}
void
LogLock
::
wlock
()
{
pid_t
caller_id
=
syscall
(
SYS_gettid
);
if
(
this
->
owner_id
==
caller_id
)
{
if
(
this
->
write_count
)
{
++
this
->
write_count
;
return
;
}
}
pthread_mutex_lock
(
&
this
->
guard
);
pid_t
owner_id
=
this
->
owner_id
;
if
(
owner_id
!=
caller_id
)
{
if
(
this
->
readers_nb
>
0
)
{
if
(
owner_id
==
CyObject_MANY_OWNERS
)
{
pthread_mutex_lock
(
&
(
LogLock
::
log_guard
));
printf
(
"Contention with several other reader threads detected while wlocking lock [%p] in thread #%d:
\n
"
"
\n
"
,
this
,
caller_id
);
pthread_mutex_unlock
(
&
(
LogLock
::
log_guard
));
}
else
{
pthread_mutex_lock
(
&
(
LogLock
::
log_guard
));
printf
(
"Contention with a reader thread detected while wlocking lock [%p] in thread #%d:
\n
"
" - reader thread is %d
\n
"
"
\n
"
,
this
,
caller_id
,
owner_id
);
pthread_mutex_unlock
(
&
(
LogLock
::
log_guard
));
}
}
while
(
this
->
readers_nb
>
0
)
{
pthread_cond_wait
(
&
this
->
wait_readers_depart
,
&
this
->
guard
);
}
if
(
this
->
write_count
>
0
)
{
pthread_mutex_lock
(
&
(
LogLock
::
log_guard
));
printf
(
"Contention with another writer detected while wlocking lock [%p] in thread #%d:
\n
"
" - lock was already wlocked by thread %d
\n
"
"
\n
"
,
this
,
caller_id
,
owner_id
);
pthread_mutex_unlock
(
&
(
LogLock
::
log_guard
));
}
while
(
this
->
write_count
>
0
)
{
pthread_cond_wait
(
&
this
->
wait_writer_depart
,
&
this
->
guard
);
}
this
->
owner_id
=
caller_id
;
}
this
->
write_count
=
1
;
pthread_mutex_unlock
(
&
this
->
guard
);
}
/*
* Atomic counter increment and decrement implementation based on
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment