From 9a5e0ede7c86b1fc213948332ae09a14a2d4729e Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 29 Jul 2011 23:21:57 +0100 Subject: [PATCH] For all Util.FireAndForget invocations, set thread to en_US before continuing wtih the invocation. This is to avoid bugs where the locale is not manually set on the thread and bad data values get sent to the database or over the wire. Lots of code does this manually but as we've seen, a subtle change can hit code which has forgotton to do this. Since en_US show be used throughout the server at present, setting it at FireAndForget seems reasonable. Arguably, it would be better to do this where data is sent, but doing it here is much easier. All the manual BeginInvokes() remaining in the code should probably call FireAndForget instead. --- OpenSim/Framework/Util.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index fce8999912..984a7a81f7 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1499,25 +1499,30 @@ namespace OpenSim.Framework public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { + // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture + // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas + // for decimals places but is read by a culture that treats commas as number seperators. + WaitCallback realCallback = delegate(object o) { Culture.SetCurrentCulture(); callback(o); }; + switch (FireAndForgetMethod) { case FireAndForgetMethod.UnsafeQueueUserWorkItem: - ThreadPool.UnsafeQueueUserWorkItem(callback, obj); + ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); break; case FireAndForgetMethod.QueueUserWorkItem: - ThreadPool.QueueUserWorkItem(callback, obj); + ThreadPool.QueueUserWorkItem(realCallback, obj); break; case FireAndForgetMethod.BeginInvoke: FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; - wrapper.FireAndForget(callback, obj); + wrapper.FireAndForget(realCallback, obj); break; case FireAndForgetMethod.SmartThreadPool: if (m_ThreadPool == null) m_ThreadPool = new SmartThreadPool(2000, 15, 2); - m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { callback, obj }); + m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); break; case FireAndForgetMethod.Thread: - Thread thread = new Thread(delegate(object o) { callback(o); }); + Thread thread = new Thread(delegate(object o) { realCallback(o); }); thread.Start(obj); break; default: