Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
Pyston
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
Pyston
Commits
3cbfac42
Commit
3cbfac42
authored
Jun 09, 2014
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use signals to get the registers of other threads
parent
fee15977
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
198 additions
and
31 deletions
+198
-31
src/Makefile
src/Makefile
+1
-1
src/core/threading.cpp
src/core/threading.cpp
+159
-7
src/core/threading.h
src/core/threading.h
+27
-6
src/gc/collector.cpp
src/gc/collector.cpp
+6
-0
src/jit.cpp
src/jit.cpp
+1
-0
src/runtime/builtin_modules/thread.cpp
src/runtime/builtin_modules/thread.cpp
+4
-17
No files found.
src/Makefile
View file @
3cbfac42
...
...
@@ -293,7 +293,7 @@ run_unittests:: run_$1_unittests
endef
override
GDB_CMDS
?=
override GDB_CMDS
:
= --ex "set confirm off" --ex run --ex "bt 20" $(GDB_CMDS)
override GDB_CMDS
:
= --ex "set confirm off" --ex
"handle SIGUSR2 pass nostop noprint" --ex
run --ex "bt 20" $(GDB_CMDS)
BR
?=
ARGS
?=
ifneq
($(BR),)
...
...
src/core/threading.cpp
View file @
3cbfac42
...
...
@@ -14,18 +14,172 @@
#include "core/threading.h"
#include <
cassert
>
#include <
atomic
>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <pthread.h>
#include <stdint.h>
#include <err.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "core/common.h"
#include "core/options.h"
namespace
pyston
{
namespace
threading
{
// Linux specific: TODO should be in a plat/linux/ directory?
pid_t
gettid
()
{
pid_t
tid
=
syscall
(
SYS_gettid
);
assert
(
tid
>
0
);
return
tid
;
}
int
tgkill
(
int
tgid
,
int
tid
,
int
sig
)
{
return
syscall
(
SYS_tgkill
,
tgid
,
tid
,
sig
);
}
class
LockedRegion
{
private:
pthread_mutex_t
*
mutex
;
public:
LockedRegion
(
pthread_mutex_t
*
mutex
)
:
mutex
(
mutex
)
{
pthread_mutex_lock
(
mutex
);
}
~
LockedRegion
()
{
pthread_mutex_unlock
(
mutex
);
}
};
// Certain thread examination functions won't be valid for a brief
// period while a thread is starting up.
// To handle this, track the number of threads in an uninitialized state,
// and wait until they start up.
int
num_starting_threads
(
0
);
struct
ThreadStartArgs
{
void
*
(
*
start_func
)(
Box
*
,
Box
*
,
Box
*
);
Box
*
arg1
,
*
arg2
,
*
arg3
;
};
static
pthread_mutex_t
threading_lock
=
PTHREAD_MUTEX_INITIALIZER
;
static
std
::
vector
<
pid_t
>
current_threads
;
static
std
::
atomic
<
int
>
signals_waiting
(
0
);
static
std
::
vector
<
ThreadState
>
thread_states
;
std
::
vector
<
ThreadState
>
getAllThreadStates
()
{
// TODO need to prevent new threads from starting,
// though I suppose that will have been taken care of
// by the caller of this function.
LockedRegion
_lock
(
&
threading_lock
);
while
(
true
)
{
// TODO shouldn't busy-wait:
if
(
num_starting_threads
)
{
pthread_mutex_unlock
(
&
threading_lock
);
sleep
(
0
);
pthread_mutex_lock
(
&
threading_lock
);
}
else
{
break
;
}
}
signals_waiting
=
(
current_threads
.
size
()
-
1
);
thread_states
.
clear
();
pid_t
tgid
=
getpid
();
pid_t
mytid
=
gettid
();
for
(
pid_t
tid
:
current_threads
)
{
if
(
tid
==
mytid
)
continue
;
tgkill
(
tgid
,
tid
,
SIGUSR2
);
}
// TODO shouldn't busy-wait:
while
(
signals_waiting
)
{
pthread_mutex_unlock
(
&
threading_lock
);
sleep
(
0
);
pthread_mutex_lock
(
&
threading_lock
);
}
assert
(
num_starting_threads
==
0
);
return
std
::
move
(
thread_states
);
}
static
void
_thread_context_dump
(
int
signum
,
siginfo_t
*
info
,
void
*
_context
)
{
LockedRegion
_lock
(
&
threading_lock
);
ucontext_t
*
context
=
static_cast
<
ucontext_t
*>
(
_context
);
if
(
VERBOSITY
())
{
pid_t
tid
=
gettid
();
printf
(
"in thread_context_dump, tid=%d
\n
"
,
tid
);
printf
(
"%p %p %p
\n
"
,
context
,
&
context
,
context
->
uc_mcontext
.
fpregs
);
printf
(
"old rip: 0x%lx
\n
"
,
context
->
uc_mcontext
.
gregs
[
REG_RIP
]);
}
thread_states
.
push_back
(
ThreadState
(
context
->
uc_mcontext
.
gregs
));
signals_waiting
--
;
// atomic on std::atomic
}
void
registerMainThread
()
{
LockedRegion
_lock
(
&
threading_lock
);
current_threads
.
push_back
(
gettid
());
struct
sigaction
act
=
{
.
sa_flags
=
SA_SIGINFO
,
.
sa_sigaction
=
_thread_context_dump
,
};
struct
sigaction
oldact
;
int
code
=
sigaction
(
SIGUSR2
,
&
act
,
&
oldact
);
if
(
code
)
err
(
1
,
NULL
);
}
static
void
*
_thread_start
(
void
*
_arg
)
{
pid_t
tid
=
gettid
();
ThreadStartArgs
*
arg
=
static_cast
<
ThreadStartArgs
*>
(
_arg
);
auto
start_func
=
arg
->
start_func
;
Box
*
arg1
=
arg
->
arg1
;
Box
*
arg2
=
arg
->
arg2
;
Box
*
arg3
=
arg
->
arg3
;
delete
arg
;
{
LockedRegion
_lock
(
&
threading_lock
);
current_threads
.
push_back
(
tid
);
num_starting_threads
--
;
if
(
VERBOSITY
()
>=
2
)
printf
(
"child initialized; tid=%d
\n
"
,
tid
);
}
threading
::
GLReadRegion
_glock
;
return
start_func
(
arg1
,
arg2
,
arg3
);
}
intptr_t
start_thread
(
void
*
(
*
start_func
)(
Box
*
,
Box
*
,
Box
*
),
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
)
{
{
LockedRegion
_lock
(
&
threading_lock
);
num_starting_threads
++
;
}
ThreadStartArgs
*
args
=
new
ThreadStartArgs
({
.
start_func
=
start_func
,
.
arg1
=
arg1
,
.
arg2
=
arg2
,
.
arg3
=
arg3
});
pthread_t
thread_id
;
int
code
=
pthread_create
(
&
thread_id
,
NULL
,
&
_thread_start
,
args
);
assert
(
code
==
0
);
if
(
VERBOSITY
()
>=
2
)
printf
(
"pthread thread_id: 0x%lx
\n
"
,
thread_id
);
static_assert
(
sizeof
(
pthread_t
)
<=
sizeof
(
intptr_t
),
""
);
return
thread_id
;
}
#if THREADING_USE_GIL
pthread_mutex_t
gil
=
PTHREAD_MUTEX_INITIALIZER
;
static
pthread_mutex_t
gil
=
PTHREAD_MUTEX_INITIALIZER
;
void
acquireGLWrite
()
{
pthread_mutex_lock
(
&
gil
);
...
...
@@ -34,9 +188,7 @@ void acquireGLWrite() {
void
releaseGLWrite
()
{
pthread_mutex_unlock
(
&
gil
);
}
#endif
}
// namespace threading
}
// namespace pyston
src/core/threading.h
View file @
3cbfac42
...
...
@@ -15,9 +15,30 @@
#ifndef PYSTON_CORE_THREADING_H
#define PYSTON_CORE_THREADING_H
#include <cstdint>
#include <cstring>
#include <ucontext.h>
#include <vector>
namespace
pyston
{
class
Box
;
namespace
threading
{
intptr_t
start_thread
(
void
*
(
*
start_func
)(
Box
*
,
Box
*
,
Box
*
),
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
);
void
registerMainThread
();
struct
ThreadState
{
gregset_t
gregs
;
ThreadState
(
gregset_t
gregs
)
{
memcpy
(
this
->
gregs
,
gregs
,
sizeof
(
gregset_t
));
}
};
// Gets a ThreadState per thread, not including the thread calling this function.
// For this call to make sense, the threads all should be blocked;
// as a corollary, this thread is very much not thread safe.
std
::
vector
<
ThreadState
>
getAllThreadStates
();
#define THREADING_USE_GIL 1
#define THREADING_USE_GRWL 0
#define THREADING_SAFE_DATASTRUCTURES THREADING_USE_GRWL
...
...
@@ -45,12 +66,12 @@ inline void demoteGL() {
}
#endif
#define MAKE_REGION(name, start, end) \
class name {
\
public:
\
name() { start(); }
\
~name() { end(); }
\
};
#define MAKE_REGION(name, start, end)
\
class name {
\
public:
\
name() { start(); }
\
~name() { end(); }
\
};
MAKE_REGION
(
GLReadRegion
,
acquireGLRead
,
releaseGLRead
);
MAKE_REGION
(
GLPromoteRegion
,
promoteGL
,
demoteGL
);
...
...
src/gc/collector.cpp
View file @
3cbfac42
...
...
@@ -20,6 +20,7 @@
#include "codegen/codegen.h"
#include "core/common.h"
#include "core/threading.h"
#include "core/types.h"
#include "gc/heap.h"
#include "gc/root_finder.h"
...
...
@@ -158,6 +159,11 @@ void runCollection() {
static
StatCounter
sc
(
"gc_collections"
);
sc
.
log
();
threading
::
GLPromoteRegion
_lock
;
std
::
vector
<
threading
::
ThreadState
>
threads
=
threading
::
getAllThreadStates
();
assert
(
threads
.
size
()
==
0
);
if
(
VERBOSITY
(
"gc"
)
>=
2
)
printf
(
"Collection #%d
\n
"
,
++
ncollections
);
...
...
src/jit.cpp
View file @
3cbfac42
...
...
@@ -108,6 +108,7 @@ int main(int argc, char** argv) {
// end of argument parsing
threading
::
registerMainThread
();
threading
::
GLReadRegion
_glock
;
_t
.
split
(
"to run"
);
...
...
src/runtime/builtin_modules/thread.cpp
View file @
3cbfac42
...
...
@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <pthread.h>
#include <stddef.h>
#include "codegen/compvars.h"
...
...
@@ -25,21 +24,11 @@ using namespace pyston::threading;
namespace
pyston
{
static_assert
(
sizeof
(
pthread_t
)
<=
sizeof
(
BoxedInt
::
n
),
""
);
BoxedModule
*
thread_module
;
static
void
*
thread_start
(
void
*
_args
)
{
threading
::
GLReadRegion
_glock
;
std
::
vector
<
Box
*>*
args
=
static_cast
<
std
::
vector
<
Box
*>*>
(
_args
);
assert
(
args
->
size
()
==
2
||
args
->
size
()
==
3
);
Box
*
target
=
(
*
args
)[
0
];
Box
*
varargs
=
(
*
args
)[
1
];
Box
*
kwargs
=
NULL
;
if
(
args
->
size
()
>
2
)
kwargs
=
(
*
args
)[
2
];
delete
args
;
static
void
*
thread_start
(
Box
*
target
,
Box
*
varargs
,
Box
*
kwargs
)
{
assert
(
target
);
assert
(
varargs
);
try
{
runtimeCall
(
target
,
ArgPassSpec
(
0
,
0
,
true
,
kwargs
!=
NULL
),
varargs
,
kwargs
,
NULL
,
NULL
,
NULL
);
...
...
@@ -53,9 +42,7 @@ static void* thread_start(void* _args) {
// TODO this should take kwargs, which defaults to empty
Box
*
startNewThread
(
Box
*
target
,
Box
*
args
)
{
pthread_t
thread_id
;
int
code
=
pthread_create
(
&
thread_id
,
NULL
,
&
thread_start
,
new
std
::
vector
<
Box
*>
({
target
,
args
}));
assert
(
code
==
0
);
intptr_t
thread_id
=
start_thread
(
&
thread_start
,
target
,
args
,
NULL
);
return
boxInt
(
thread_id
^
0x12345678901L
);
}
...
...
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