]> git.proxmox.com Git - rustc.git/blame - src/librustc/dep_graph/thread.rs
Imported Upstream version 1.11.0+dfsg1
[rustc.git] / src / librustc / dep_graph / thread.rs
CommitLineData
9cc50fc6
SL
1// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Manages the communication between the compiler's main thread and
12//! the thread that constructs the dependency graph. The basic idea is
13//! to use double buffering to lower the cost of producing a message.
14//! In the compiler thread, we accumulate messages in a vector until
15//! the vector is full, or until we want to query the graph, and then
16//! we send that vector over to the depgraph thread. At the same time,
17//! we receive an empty vector from the depgraph thread that we can use
18//! to accumulate more messages. This way we only ever have two vectors
19//! allocated (and both have a fairly large capacity).
20
54a0048b 21use hir::def_id::DefId;
9cc50fc6 22use rustc_data_structures::veccell::VecCell;
7453a54e 23use std::cell::Cell;
9cc50fc6
SL
24use std::sync::mpsc::{self, Sender, Receiver};
25use std::thread;
26
27use super::DepGraphQuery;
28use super::DepNode;
29use super::edges::DepGraphEdges;
30
a7813a04 31#[derive(Debug)]
9cc50fc6 32pub enum DepMessage {
54a0048b
SL
33 Read(DepNode<DefId>),
34 Write(DepNode<DefId>),
35 PushTask(DepNode<DefId>),
36 PopTask(DepNode<DefId>),
9cc50fc6
SL
37 PushIgnore,
38 PopIgnore,
39 Query,
40}
41
42pub struct DepGraphThreadData {
43 enabled: bool,
44
7453a54e
SL
45 // Local counter that just tracks how many tasks are pushed onto the
46 // stack, so that we still get an error in the case where one is
47 // missing. If dep-graph construction is enabled, we'd get the same
48 // error when processing tasks later on, but that's annoying because
49 // it lacks precision about the source of the error.
50 tasks_pushed: Cell<usize>,
51
9cc50fc6
SL
52 // current buffer, where we accumulate messages
53 messages: VecCell<DepMessage>,
54
55 // whence to receive new buffer when full
56 swap_in: Receiver<Vec<DepMessage>>,
57
58 // where to send buffer when full
59 swap_out: Sender<Vec<DepMessage>>,
60
61 // where to receive query results
54a0048b 62 query_in: Receiver<DepGraphQuery<DefId>>,
9cc50fc6
SL
63}
64
65const INITIAL_CAPACITY: usize = 2048;
66
67impl DepGraphThreadData {
68 pub fn new(enabled: bool) -> DepGraphThreadData {
69 let (tx1, rx1) = mpsc::channel();
70 let (tx2, rx2) = mpsc::channel();
71 let (txq, rxq) = mpsc::channel();
7453a54e 72
9cc50fc6
SL
73 if enabled {
74 thread::spawn(move || main(rx1, tx2, txq));
75 }
7453a54e 76
9cc50fc6
SL
77 DepGraphThreadData {
78 enabled: enabled,
7453a54e 79 tasks_pushed: Cell::new(0),
9cc50fc6
SL
80 messages: VecCell::with_capacity(INITIAL_CAPACITY),
81 swap_in: rx2,
82 swap_out: tx1,
83 query_in: rxq,
84 }
85 }
86
7453a54e
SL
87 #[inline]
88 pub fn enabled(&self) -> bool {
89 self.enabled
90 }
91
9cc50fc6
SL
92 /// Sends the current batch of messages to the thread. Installs a
93 /// new vector of messages.
94 fn swap(&self) {
95 assert!(self.enabled, "should never swap if not enabled");
96
97 // should be a buffer waiting for us (though of course we may
98 // have to wait for depgraph thread to finish processing the
99 // old messages)
100 let new_messages = self.swap_in.recv().unwrap();
101 assert!(new_messages.is_empty());
102
103 // swap in the empty buffer and extract the full one
104 let old_messages = self.messages.swap(new_messages);
105
106 // send full buffer to depgraph thread to be processed
107 self.swap_out.send(old_messages).unwrap();
108 }
109
54a0048b 110 pub fn query(&self) -> DepGraphQuery<DefId> {
9cc50fc6
SL
111 assert!(self.enabled, "cannot query if dep graph construction not enabled");
112 self.enqueue(DepMessage::Query);
113 self.swap();
114 self.query_in.recv().unwrap()
115 }
116
117 /// Enqueue a message to be sent when things are next swapped. (If
118 /// the buffer is full, this may swap.)
119 #[inline]
120 pub fn enqueue(&self, message: DepMessage) {
7453a54e
SL
121 // Regardless of whether dep graph construction is enabled, we
122 // still want to check that we always have a valid task on the
123 // stack when a read/write/etc event occurs.
124 match message {
125 DepMessage::Read(_) | DepMessage::Write(_) =>
126 if self.tasks_pushed.get() == 0 {
127 self.invalid_message("read/write but no current task")
128 },
129 DepMessage::PushTask(_) | DepMessage::PushIgnore =>
130 self.tasks_pushed.set(self.tasks_pushed.get() + 1),
131 DepMessage::PopTask(_) | DepMessage::PopIgnore =>
132 self.tasks_pushed.set(self.tasks_pushed.get() - 1),
133 DepMessage::Query =>
134 (),
135 }
136
9cc50fc6 137 if self.enabled {
7453a54e
SL
138 self.enqueue_enabled(message);
139 }
140 }
141
142 // Outline this fn since I expect it may want to be inlined
143 // separately.
144 fn enqueue_enabled(&self, message: DepMessage) {
145 let len = self.messages.push(message);
146 if len == INITIAL_CAPACITY {
147 self.swap();
9cc50fc6
SL
148 }
149 }
7453a54e
SL
150
151 // Outline this too.
152 fn invalid_message(&self, string: &str) {
54a0048b 153 bug!("{}; see src/librustc/dep_graph/README.md for more information", string)
7453a54e 154 }
9cc50fc6
SL
155}
156
157/// Definition of the depgraph thread.
158pub fn main(swap_in: Receiver<Vec<DepMessage>>,
159 swap_out: Sender<Vec<DepMessage>>,
54a0048b 160 query_out: Sender<DepGraphQuery<DefId>>) {
9cc50fc6
SL
161 let mut edges = DepGraphEdges::new();
162
163 // the compiler thread always expects a fresh buffer to be
164 // waiting, so queue one up
165 swap_out.send(Vec::with_capacity(INITIAL_CAPACITY)).unwrap();
166
167 // process the buffers from compiler thread as we receive them
168 for mut messages in swap_in {
169 for msg in messages.drain(..) {
170 match msg {
171 DepMessage::Read(node) => edges.read(node),
172 DepMessage::Write(node) => edges.write(node),
173 DepMessage::PushTask(node) => edges.push_task(node),
174 DepMessage::PopTask(node) => edges.pop_task(node),
175 DepMessage::PushIgnore => edges.push_ignore(),
176 DepMessage::PopIgnore => edges.pop_ignore(),
177 DepMessage::Query => query_out.send(edges.query()).unwrap(),
178 }
179 }
a7813a04
XL
180 if let Err(_) = swap_out.send(messages) {
181 // the receiver must have been dropped already
182 break;
183 }
9cc50fc6
SL
184 }
185}