Skip to content

Commit b2a6fd2

Browse files
committed
Fix tectonic-typesetting#5: use thread local client
Reqwest client should be destroyed before forking to avoid threading issue. This is done by using thread local storage, that is initialized and used by geturl and cleared by texpresso. Alternative: use pthread_atfork in reqwest to properly handle fork.
1 parent c2f9422 commit b2a6fd2

File tree

4 files changed

+34
-4
lines changed

4 files changed

+34
-4
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/geturl/src/reqwest.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,37 @@ use reqwest::{
1111
};
1212
use tectonic_errors::{anyhow::bail, Result};
1313
use tectonic_status_base::{tt_note, StatusBackend};
14+
use std::cell::RefCell;
1415

1516
use crate::{GetUrlBackend, RangeReader};
1617

1718
const MAX_HTTP_REDIRECTS_ALLOWED: usize = 10;
1819

20+
thread_local!(static SHARED_CLIENT: RefCell<Option<Client>> = RefCell::new(None));
21+
22+
fn get_shared_client() -> Client {
23+
SHARED_CLIENT.with(|rclient| {
24+
let mut oclient = rclient.borrow_mut();
25+
match oclient.to_owned() {
26+
Some(client) => client,
27+
None => {
28+
let client = Client::new();
29+
*oclient = Some(client.clone());
30+
client
31+
}
32+
}
33+
})
34+
}
35+
36+
/// Drop the shared client.
37+
/// It maintains a connection pool that causes problem when forking.
38+
pub fn clear_shared_client() {
39+
SHARED_CLIENT.with(|rclient| {
40+
let mut oclient = rclient.borrow_mut();
41+
*oclient = None
42+
})
43+
}
44+
1945
/// URL-get backend implemented using the `reqwest` crate.
2046
#[derive(Debug, Default)]
2147
pub struct ReqwestBackend {}
@@ -25,7 +51,7 @@ impl GetUrlBackend for ReqwestBackend {
2551
type RangeReader = ReqwestRangeReader;
2652

2753
fn get_url(&mut self, url: &str, _status: &mut dyn StatusBackend) -> Result<Response> {
28-
let res = Client::new().get(url).send()?;
54+
let res = get_shared_client().get(url).send()?;
2955
if !res.status().is_success() {
3056
bail!(
3157
"unexpected HTTP response code {} for URL {}",
@@ -114,14 +140,14 @@ impl GetUrlBackend for ReqwestBackend {
114140
#[derive(Debug)]
115141
pub struct ReqwestRangeReader {
116142
url: String,
117-
client: Client,
143+
//client: Rc<Client>,
118144
}
119145

120146
impl ReqwestRangeReader {
121147
fn new(url: &str) -> ReqwestRangeReader {
122148
ReqwestRangeReader {
123149
url: url.to_owned(),
124-
client: Client::new(),
150+
//client: Rc::new(Client::new()),
125151
}
126152
}
127153
}
@@ -136,7 +162,8 @@ impl RangeReader for ReqwestRangeReader {
136162
let mut headers = HeaderMap::new();
137163
headers.insert(RANGE, header_val);
138164

139-
let res = self.client.get(&self.url).headers(headers).send()?;
165+
let client = get_shared_client();
166+
let res = client.get(&self.url).headers(headers).send()?;
140167

141168
if res.status() != StatusCode::PARTIAL_CONTENT {
142169
bail!(

crates/io_base/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ sha2 = "^0.10" # for digest computations
2323
thiserror = "1.0"
2424
tectonic_errors = { path = "../errors", version =">=0.1.0,<1"}
2525
tectonic_status_base = { path = "../status_base", version =">=0.1.0,<1"}
26+
tectonic_geturl = { path = "../geturl", version =">=0.3.0,<1" }
2627
texpresso_protocol = { path = "../texpresso_protocol", version = "0.1.0" }
2728

2829
[package.metadata.internal_dep_versions]

crates/io_base/src/texpresso.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ impl io::Read for TexpressoReader {
115115
None => {
116116
io.client.flush();
117117
io.gen += 1;
118+
tectonic_geturl::reqwest::clear_shared_client();
118119
let child = unsafe { io.client.fork() };
119120
if child == 0 {
120121
io.client.child(unsafe{libc::getpid()})

0 commit comments

Comments
 (0)