-
Notifications
You must be signed in to change notification settings - Fork 3
/
README.threads
108 lines (101 loc) · 5.25 KB
/
README.threads
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
In order to debug a threaded application, you need
to link with -lcwd_r instead of -lcwd.
Threading only works on linux so far.
Use ./configure --disable-threading on other OS.
A core dump produced by a kernel 2.4 does not
contain enough information for gdb to debug all
threads. Only the core dumping thread is dumped
and the other threads continue to run for a while.
There exists a kernel patch written by Intel/IBM
that fixes this problem; please read
http://www-124.ibm.com/developer/opensource/linux/projects/mtcoredumps/
Note: This patch, multithreaded coredumps support patch, has
already been included in kernel 2.5.47 and higher.
The minimal version of gdb needed to debug multi-threaded
applications in a meaningful way has always been 5.2. However,
when using g++ 3.x or higher, you should be using at least gdb 6.0
(but using the _latest_ version of gdb is always the best idea!).
Try not to use -O2 or -fomit-frame-pointer if you want source
file and line numbers that make sense ;).
Be aware that gdb does hardly support namespaces and
will therefore frequently not find types or variables
in namespaces. It doesn't look like that this will be
fixed very soon (2002-05-27) (see the thread that belongs
to http://sources.redhat.com/ml/gdb/2002-05/msg00278.html)
In order to specify namespaces in gdb you will have to
type them in full and put single quotes around it.
For example:
(gdb) p *(('some::name::space::ptr'*)0x8039214)
In order to debug NPTL (Native POSIX Threads Library)
you will need the gdb that comes with RedHat 9 (or fedora).
At the moment of writing (2003/6/27), the CVS HEAD of gdb
does not work with NPTL.
As of libcwd-0.99.31, support for NPTL was added. The
Thread Specific Data of libcwd now works as follows:
1) The first two calls to calloc() are assumed not to
be internal but to be part of the initialization
of libpthread. At that moment there is no thread
specific (or thread local) storage possible.
The location lookup and the inclusion on the map<>
that stores all allocations is delayed till the
third call to calloc(). This call is assumed to
be done before we reach main(). The two first
calloc's are added as invisible allocations (don't
show up in list_allocations_on()).
2) While configuring libcwd, the environment variable
THREADSMAX is used as the maximum number of simultaneous
running threads. At the moment this means that
this is the size of a static array with basic
Thread Specific Data (TSD) for libcwd (basic because
it doesn't contain the TSD that is needed to actually
write debug output: debug output is turned off).
When a new thread calls malloc(), or new, for the
first time (or any other libcwd function, most likely
turning on libcw_do or a debug channel), it is
detected that this is a new thread and the new thread
gets assigned one of the entries of this static array
to be used as TSD. As soon as possible the TSD is
initialized fully (so writing debug output becomes
possible) and a pthread key is added to be used as TSD.
After initialization (a few miliseconds(?) after thread
creation) the static array TSD is released again
and the new thread now uses the pthread key.
3) When a thread terminates, libpthread will call a
destructor call back function of the above key - along
with any other user provided call backs for other keys.
The destructor routine of the libcwd key will re-add
itself three times without taking action, allowing
user destructor routines to finish first,
still able to use libcwd at that moment. Finally
it will release the key and move the TSD back to
a free entry in the static array. From that moment
on debug output is inhibited, but no user code will
be called anymore usually. Basically, all that
happens after that is that libpthread possibly calls
free() to release the second level key hash table(s)
it has (once per 32 keys). These frees will then not
be visible. It is not possible to exactly determine
when a thread finishes - therefore the following
trick is being used: When a TSD struct is requested
from within a call to free() (or delete to accommodate
possible user key destruction routines that also re-add
themselfs, or other keys, recursively more often than
PTHREAD_DESTRUCTOR_ITERATIONS and which are called
later then libcwd's destructor routine, and which use
delete), then the existing static TSD is returned
and when there is no static TSD that matches the
thread - it is assumed that the array was full, and
a new static TSD is returned without initializing it
or creating a new pthread key for it (it is marked
again as a 'terminating' thread). However, when a TSD
is requested from anywhere else - then libcwd assumes
this is a NEW thread, and the TSD will be initialized
when it doesn't already exist.
IMPORTANT: This means that you are not allowed to *allocate*
memory, or to write debug output (or use any other libcwd
function), from a key destructor routine of a key that is
added recursively from another, or the same, key destructor
routine.
The best thing to do is to avoid using pthread_setspecific()
inside a key destructor routine - or at least not do that
more often than PTHREAD_DESTRUCTOR_ITERATIONS - 2 times.