summaryrefslogtreecommitdiff
path: root/README.THREADS
blob: fd569194fe93a9ce2b6d2a7ab39db7e1f5d18d08 (plain)
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
  The basic threading philosophy followed in aptitude can be
summarized thus: "if you aren't sure it's safe, do it in the main
thread; if it's going to take a long time, try to make it safe to run
in the background".  The mechanism for doing so is
interface-dependent: for the curses frontend, it's
cwidget::toplevel::post_event (cwidget/toplevel.h), and for the GTK+
frontend, it's gui::post_event.  Both of these functions place a
callback object into the global event queue and wake up the main
thread (if necessary).

  The actual threading constructs used are the pthread wrappers in
cwidget/generic/threads.h (and also cwidget/generic/event_queue.h).

  Background threads are spawned to do long-running operations, but they
generally only access data that is "owned" by the thread.  More
details on the currently existing background threads below.

  These threads generally take some sort of "continuation" object
that's invoked when the background process is finished; it's expected
that this object will probably post some sort of event to the main
thread.

  Several of aptitude's background threads exist to serialize work
that's too time-consuming to perform in the main thread.  The template
job_event_queue (in src/generic/util/job_event_queue.h) provides a
generic implementation of this behavior via the Curiously Recurring
Template Pattern.


  Things that you might thank are threadsafe but aren't include:

  * sigc++ objects.  Not only do you have to watch out for manual
    additions and deletions to connection lists during invocation, you
    also have to watch out for automatic invalidation of slots at any
    time.  Best practice here is to confine sigc++ access to the main
    thread, or to use safe_slot (but read the caveats in its header).

  * Smart pointers other than boost::shared_ptr.  Most smart pointers
    that aptitude uses are NOT threadsafe.  This means that *EVEN
    READ-ONLY ACCESS* from another thread will cause horrible ghastly
    problems that you don't even want to think about.  At the moment
    it's almost never necessary to pass these between threads, so it's
    not a big deal; the exception is the problem resolver's solution
    objects (and the shared trees contained inside them), which are
    dealt with by doing a deep copy of the object. (see
    resolver_manager::do_get_solution)

    The reason this is the case is basically that the pthread
    abstraction doesn't give you a fast lock for low-contention
    situations -- adding locking around the reference counts of set
    tree nodes made the overall resolver take 50% longer to run in
    single-threaded mode!  I'm not eager to add nonportable threading
    constructs, so I decided to see whether it was possible to just be
    very careful about handling reference-counted objects.

Existing background threads:

  * The cwidget library creates threads to handle keyboard input,
    certain asynchronous signals, and timed events.  You generally
    don't need to worry about these.

  * Downloads are performed by a background thread.  In keeping with
    the overall philosophy, only the actual download is handled in
    this way -- the setup of the download and any actions taken once
    it completes are handled by the main thread.  The gatekeeper for
    downloads is in download_thread.cc; it provides the basic thread
    harness, as well as a convenience class that forwards the various
    download messages to a foreground progress meter.  (these are
    basically inter-thread RPC calls, and they block the download
    thread until the progress meter's method call returns a value)

  * The problem resolver runs in a background thread.  This thread
    always exists, even when there is no resolver (in which case it
    will just sleep); the foreground thread can post jobs to it, and
    will also stop the resolver whenever its state needs to be
    modified (for instance, if the rejected set is changed).  The
    interface for this is in src/generic/resolver_manager.cc.

  * From the GTK+ interface, changelog parsing and checking for
    changelogs in the download cache both happen in a background
    thread.