Wrap all LLVM API calls with a single mutex when LLVM doesn't have multithreaded
mode.
Also fallback to interpreter mode on i386 and i486.
... | ... |
@@ -45,6 +45,7 @@ |
45 | 45 |
#include "llvm/Support/IRBuilder.h" |
46 | 46 |
#include "llvm/Support/PrettyStackTrace.h" |
47 | 47 |
#include "llvm/System/DataTypes.h" |
48 |
+#include "llvm/System/Host.h" |
|
48 | 49 |
#include "llvm/System/Mutex.h" |
49 | 50 |
#include "llvm/System/Signals.h" |
50 | 51 |
#include "llvm/System/Threading.h" |
... | ... |
@@ -60,8 +61,8 @@ |
60 | 60 |
#include <new> |
61 | 61 |
|
62 | 62 |
#include "llvm/Config/config.h" |
63 |
-#if !defined(LLVM_MULTITHREADED) || !LLVM_MULTITHREADED |
|
64 |
-#error "Multithreading support must be available to LLVM!" |
|
63 |
+#if !ENABLE_THREADS |
|
64 |
+#error "Thread support was explicitly disabled. Cannot continue" |
|
65 | 65 |
#endif |
66 | 66 |
|
67 | 67 |
#ifdef HAVE_CONFIG_H |
... | ... |
@@ -1211,11 +1212,33 @@ public: |
1211 | 1211 |
return true; |
1212 | 1212 |
} |
1213 | 1213 |
}; |
1214 |
+ |
|
1215 |
+static sys::Mutex llvm_api_lock; |
|
1216 |
+ |
|
1217 |
+// This class automatically acquires the lock when instantiated, |
|
1218 |
+// and releases the lock when leaving scope. |
|
1219 |
+class LLVMApiScopedLock { |
|
1220 |
+ public: |
|
1221 |
+ // when multithreaded mode is false (no atomics available), |
|
1222 |
+ // we need to wrap all LLVM API calls with a giant mutex lock, but |
|
1223 |
+ // only then. |
|
1224 |
+ LLVMApiScopedLock() { |
|
1225 |
+ if (!llvm_is_multithreaded()) |
|
1226 |
+ llvm_api_lock.acquire(); |
|
1227 |
+ } |
|
1228 |
+ ~LLVMApiScopedLock() { |
|
1229 |
+ if (!llvm_is_multithreaded()) |
|
1230 |
+ llvm_api_lock.release(); |
|
1231 |
+ } |
|
1232 |
+}; |
|
1233 |
+ |
|
1214 | 1234 |
} |
1215 | 1235 |
|
1216 | 1236 |
int cli_vm_execute_jit(const struct cli_all_bc *bcs, struct cli_bc_ctx *ctx, |
1217 | 1237 |
const struct cli_bc_func *func) |
1218 | 1238 |
{ |
1239 |
+ // no locks needed here, since LLVM automatically acquires a JIT lock |
|
1240 |
+ // if needed. |
|
1219 | 1241 |
jmp_buf env; |
1220 | 1242 |
void *code = bcs->engine->compiledFunctions[func]; |
1221 | 1243 |
if (!code) { |
... | ... |
@@ -1259,6 +1282,7 @@ int cli_bytecode_prepare_jit(struct cli_all_bc *bcs) |
1259 | 1259 |
if (!bcs->engine) |
1260 | 1260 |
return CL_EBYTECODE; |
1261 | 1261 |
jmp_buf env; |
1262 |
+ LLVMApiScopedLock scopedLock; |
|
1262 | 1263 |
// setup exception handler to longjmp back here |
1263 | 1264 |
ExceptionReturn.set((const jmp_buf*)&env); |
1264 | 1265 |
if (setjmp(env) != 0) { |
... | ... |
@@ -1386,8 +1410,10 @@ int cli_bytecode_prepare_jit(struct cli_all_bc *bcs) |
1386 | 1386 |
int bytecode_init(void) |
1387 | 1387 |
{ |
1388 | 1388 |
// If already initialized return |
1389 |
- if (llvm_is_multithreaded()) |
|
1390 |
- return 0; |
|
1389 |
+ if (llvm_is_multithreaded()) { |
|
1390 |
+ errs() << "bytecode_init: already initialized"; |
|
1391 |
+ return CL_EARG; |
|
1392 |
+ } |
|
1391 | 1393 |
llvm_install_error_handler(llvm_error_handler); |
1392 | 1394 |
#ifdef CL_DEBUG |
1393 | 1395 |
sys::PrintStackTraceOnErrorSignal(); |
... | ... |
@@ -1407,13 +1433,28 @@ int bytecode_init(void) |
1407 | 1407 |
// If we have a native target, initialize it to ensure it is linked in and |
1408 | 1408 |
// usable by the JIT. |
1409 | 1409 |
InitializeNativeTarget(); |
1410 |
+ |
|
1411 |
+ if (!llvm_is_multithreaded()) { |
|
1412 |
+ //TODO:cli_dbgmsg |
|
1413 |
+ DEBUG(errs() << "WARNING: ClamAV JIT built w/o atomic builtins\n" |
|
1414 |
+ << "On x86 for best performance ClamAV should be built for i686, not i386!\n"); |
|
1415 |
+ } |
|
1410 | 1416 |
return 0; |
1411 | 1417 |
} |
1412 | 1418 |
|
1413 | 1419 |
// Called once when loading a new set of BC files |
1414 | 1420 |
int cli_bytecode_init_jit(struct cli_all_bc *bcs) |
1415 | 1421 |
{ |
1416 |
- //TODO: if !llvm_is_multi... |
|
1422 |
+ LLVMApiScopedLock scopedLock; |
|
1423 |
+ std::string cpu = sys::getHostCPUName(); |
|
1424 |
+ DEBUG(errs() << "host cpu is: " << cpu << "\n"); |
|
1425 |
+ if (!cpu.compare("i386") || |
|
1426 |
+ !cpu.compare("i486")) { |
|
1427 |
+ bcs->engine = 0; |
|
1428 |
+ DEBUG(errs() << "i[34]86 detected, falling back to interpreter (JIT needs pentium or better\n"); |
|
1429 |
+ /* i386 and i486 has to fallback to interpreter */ |
|
1430 |
+ return 0; |
|
1431 |
+ } |
|
1417 | 1432 |
bcs->engine = new(std::nothrow) cli_bcengine; |
1418 | 1433 |
if (!bcs->engine) |
1419 | 1434 |
return CL_EMEM; |
... | ... |
@@ -1423,6 +1464,7 @@ int cli_bytecode_init_jit(struct cli_all_bc *bcs) |
1423 | 1423 |
|
1424 | 1424 |
int cli_bytecode_done_jit(struct cli_all_bc *bcs) |
1425 | 1425 |
{ |
1426 |
+ LLVMApiScopedLock scopedLock; |
|
1426 | 1427 |
if (bcs->engine) { |
1427 | 1428 |
if (bcs->engine->EE) |
1428 | 1429 |
delete bcs->engine->EE; |