Skip to content

Commit efdd949

Browse files
committed
Fix race condition.
1 parent 2a23c9a commit efdd949

File tree

1 file changed

+17
-1
lines changed

1 file changed

+17
-1
lines changed

roundup/cgi/templating.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,28 @@ def get(self, name, extension=None):
183183
return self.templates[src]
184184

185185
# compile the template
186-
self.templates[src] = pt = RoundupPageTemplate()
186+
pt = RoundupPageTemplate()
187187
# use pt_edit so we can pass the content_type guess too
188188
content_type = mimetypes.guess_type(filename)[0] or 'text/html'
189189
pt.pt_edit(open(src).read(), content_type)
190190
pt.id = filename
191191
pt.mtime = stime
192+
# Add it to the cache. We cannot do this until the template
193+
# is fully initialized, as we could otherwise have a race
194+
# condition when running with multiple threads:
195+
#
196+
# 1. Thread A notices the template is not in the cache,
197+
# adds it, but has not yet set "mtime".
198+
#
199+
# 2. Thread B notices the template is in the cache, checks
200+
# "mtime" (above) and crashes.
201+
#
202+
# Since Python dictionary access is atomic, as long as we
203+
# insert "pt" only after it is fully initialized, we avoid
204+
# this race condition. It's possible that two separate
205+
# threads will both do the work of initializing the template,
206+
# but the risk of wasted work is offset by avoiding a lock.
207+
self.templates[src] = pt
192208
return pt
193209

194210
def __getitem__(self, name):

0 commit comments

Comments
 (0)