瀏覽代碼

rewrite SpinLock to still work without the need to accidentally disable optimizations for a large part of the classes unit

git-svn-id: trunk@27864 -
Károly Balogh 11 年之前
父節點
當前提交
e89669bedc
共有 1 個文件被更改,包括 18 次插入5 次删除
  1. 18 5
      rtl/objpas/classes/classes.inc

+ 18 - 5
rtl/objpas/classes/classes.inc

@@ -83,6 +83,11 @@ var
   { this list holds all instances of external threads that need to be freed at
     the end of the program }
   ExternalThreads: TThreadList;
+
+  { this must be a global var, otherwise unwanted optimizations might happen in
+    TThread.SpinWait() }
+  SpinWaitDummy: LongWord;
+
 threadvar
   { the instance of the current thread; in case of an external thread this is
     Nil until TThread.GetCurrentThread was called once (the RTLs need to ensure
@@ -572,15 +577,23 @@ end;
 
 
 class procedure TThread.SpinWait(aIterations: LongWord);
+var
+  i: LongWord;
 begin
   { yes, it's just a simple busy wait to burn some cpu cycles... and as the job
     of this loop is to burn CPU cycles we switch off any optimizations that
     could interfere with this (e.g. loop unrolling) }
-{$PUSH}
-{$OPTIMIZATION OFF}
-  while aIterations > 0 do
-    Dec(aIterations);
-{$POP}
+  { Do *NOT* do $PUSH, $OPTIMIZATIONS OFF, <code>, $POP because optimization is
+    not a local switch, which means $PUSH/POP doesn't affect it, so that turns
+    off *ALL* optimizations for code below this point. Thanks to this we shipped
+    large parts of the classes unit with optimizations off between 2012-12-27
+    and 2014-06-06.
+    Instead, use a global var for the spinlock, because that is always handled
+    as volatile, so the access won't be optimized away by the compiler. (KB) }
+  for i:=1 to aIterations do
+    begin
+      Inc(SpinWaitDummy); // SpinWaitDummy *MUST* be global
+    end;
 end;