Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

add support for Linux, update to v0.5.0

  • Loading branch information...
commit e8acd8cb0c40cf8929415b2c016d2ef3cebdb1b9 1 parent 4ffc753
authored July 26, 2012
13  README.md
Source Rendered
@@ -3,7 +3,7 @@ Tripwire
3 3
 
4 4
 Tripwire allows node.js applications to termiante execution of scripts that block the node.js event loop. For example, you can break out from infinite loops like `while(true)`. This functionality is useful if you are executing untrusted code within your node.js process. 
5 5
 
6  
-Tripwire contains a native extension of node.js and currently only supports Mac and Windows. I do take contributions. 
  6
+Tripwire contains a native extension of node.js and currently supports Windows, Mac, and Linux. I do take contributions. 
7 7
 
8 8
 Install with:
9 9
 
@@ -56,14 +56,14 @@ For more samples, see [here](https://github.com/tjanczuk/tripwire/tree/master/sa
56 56
 There are a few mocha tests included that you can run with
57 57
 
58 58
 ```
59  
-mocha -R List
  59
+mocha -R list
60 60
 ```
61 61
 
62 62
 #### Building
63 63
 
64 64
 The native component is included in the repository and not built during `npm install tripwire`.
65 65
 
66  
-You can rebuild the native component using [node-gyp](https://github.com/TooTallNate/node-gyp/). Currently the native component can be compiled on Mac and Windows only (I do take contributions).
  66
+You can rebuild the native component using [node-gyp](https://github.com/TooTallNate/node-gyp/). Currently the native component can be compiled on Windows, Mac, and Linux (I do take contributions).
67 67
 
68 68
 On Windows:
69 69
 
@@ -77,4 +77,11 @@ On Mac:
77 77
 ```
78 78
 node-gyp configure build
79 79
 cp build\Release\tripwire.node lib\native\darwin\x86\
  80
+```
  81
+
  82
+On Linux:
  83
+
  84
+```
  85
+node-gyp configure build
  86
+cp build\Release\tripwire.node lib\native\linux\x86\
80 87
 ```
7  binding.gyp
@@ -15,7 +15,12 @@
15 15
       	  'sources+': [
16 16
       	    'src/tripwire_mac.cc'
17 17
       	  ]
18  
-      	}]
  18
+      	}],
  19
+        ['OS=="linux"', {
  20
+          'sources+': [
  21
+            'src/tripwire_linux.cc'
  22
+          ]
  23
+        }]
19 24
       ]
20 25
     }
21 26
   ]
BIN  lib/native/linux/x86/tripwire.node
Binary file not shown
8  lib/tripwire.js
... ...
@@ -1,7 +1,5 @@
1  
-if (process.platform === 'win32')
2  
-	module.exports = require('./native/windows/x86/tripwire');
3  
-else if (process.platform === 'darwin')
4  
-	module.exports = require('./native/darwin/x86/tripwire')
  1
+if (process.platform === 'win32' || process.platform === 'darwin' || process.platform === 'linux')
  2
+	module.exports = require('./native/' + process.platform + '/x86/tripwire')
5 3
 else
6  
-	throw new Error('The tripwire module is currently only suppored on Windows and Mac. I do take contributions. '
  4
+	throw new Error('The tripwire module is currently only suppored on Windows, Mac, and Linux. I do take contributions. '
7 5
 		+ 'https://github.com/tjanczuk/tripwire');
2  package.json
@@ -5,7 +5,7 @@
5 5
     "url": "http://tomasz.janczuk.org",
6 6
     "twitter": "tjanczuk"
7 7
   },
8  
-  "version": "0.5.0-pre",
  8
+  "version": "0.5.0",
9 9
   "description": "Break out from scripts blocking node.js event loop",
10 10
   "tags" : ["event loop", "hang"],
11 11
   "main": "./lib/tripwire.js",
140  src/tripwire_linux.cc
... ...
@@ -0,0 +1,140 @@
  1
+#include <pthread.h>
  2
+#include <sys/resource.h>
  3
+#include <errno.h>
  4
+#include <sys/time.h>
  5
+#include <node.h>
  6
+#include <v8.h>
  7
+
  8
+using namespace v8;
  9
+
  10
+pthread_t tripwireThread;
  11
+pthread_mutex_t tripwireMutex = PTHREAD_MUTEX_INITIALIZER;
  12
+pthread_cond_t tripwireCondition = PTHREAD_COND_INITIALIZER;
  13
+
  14
+extern unsigned int tripwireThreshold;
  15
+extern int terminated;
  16
+
  17
+void* tripwireWorker(void* data)
  18
+{
  19
+	int waitResult;
  20
+	int skipTimeCapture = 0;
  21
+	struct timespec timeout;
  22
+	struct rusage start, end;
  23
+
  24
+	// This thread monitors the elapsed CPU utilization time of the node.js thread and forces V8 to terminate
  25
+	// execution if it exceeds the preconfigured tripwireThreshold.
  26
+
  27
+	while (1) 
  28
+	{
  29
+		// Unless the threshold validation logic requested to keep the current thread time utilization values,
  30
+		// capture the current user mode and kernel mode CPU utilization time of the thread on which node.js executes
  31
+		// application code. 
  32
+
  33
+		if (skipTimeCapture) 
  34
+			skipTimeCapture = 0;
  35
+		else 
  36
+			getrusage(RUSAGE_SELF, &start);
  37
+			
  38
+		// Wait on the condition variable to be signalled. The variable will be signalled in one of two cases:
  39
+		// 1. When the timeout value equal to tripwireThreshold elapses, or
  40
+		// 2. When the variable is explicitly signalled from resetTripwire.
  41
+		// A tripwireThreshold value of 0 indicates the tripwire mechanism is turned off, in which case
  42
+		// an inifite wait is initiated on the variable (which will only be terminated with an explicit signal
  43
+		// during subsequent call to resetThreashold).
  44
+
  45
+		pthread_mutex_lock(&tripwireMutex);
  46
+		if (0 == tripwireThreshold) 
  47
+		{
  48
+			waitResult = pthread_cond_wait(&tripwireCondition, &tripwireMutex);
  49
+		}
  50
+		else
  51
+		{
  52
+			clock_gettime(CLOCK_REALTIME, &timeout);
  53
+			timeout.tv_sec += tripwireThreshold / 1000;
  54
+			timeout.tv_nsec += (tripwireThreshold % 1000) * 1000000;
  55
+			waitResult = pthread_cond_timedwait(&tripwireCondition, &tripwireMutex, &timeout);
  56
+		}
  57
+		pthread_mutex_unlock(&tripwireMutex);
  58
+
  59
+		if (ETIMEDOUT == waitResult) 
  60
+		{
  61
+			// If the wait result on the variable is ETIMEDOUT, it means resetThreshold
  62
+			// was not called in the tripwireThreshold period since the last call to resetThreshold. This indicates
  63
+			// a possibility that the node.js thread is blocked. 
  64
+
  65
+			// If tripwireThreshold is 0 at this point, however, it means a call to clearTripwire was made 
  66
+			// since the last call to resetThreshold. In this case we just skip tripwire enforcement and 
  67
+			// proceed to wait for a subsequent signal. 
  68
+
  69
+			if (0 < tripwireThreshold) 
  70
+			{
  71
+				// Take a snapshot of the current kernel and user mode CPU utilization time of the node.js thread
  72
+				// to determine if the elapsed CPU utilization time exceeded the preconfigured tripwireThreshold. 
  73
+				// Despite the fact this code only ever executes after the auto reset event has already timeout out 
  74
+				// after the tripwireThreshold amount of time without hearing from the node.js thread, it need not 
  75
+				// necessarily mean that the node.js thread exceeded that execution time threshold. It might not
  76
+				// have been running at all in that period, subject to OS scheduling. 
  77
+
  78
+				getrusage(RUSAGE_SELF, &end);
  79
+
  80
+				// Process execution times are reported in seconds and microseconds. Convert to milliseconds.
  81
+
  82
+				unsigned int elapsedMs = 
  83
+					((end.ru_utime.tv_sec - start.ru_utime.tv_sec) + (end.ru_stime.tv_sec - start.ru_stime.tv_sec)) 
  84
+					* 1000
  85
+					+ ((end.ru_utime.tv_usec - start.ru_utime.tv_usec) + (end.ru_stime.tv_usec - start.ru_stime.tv_usec)) 
  86
+					/ 1000;
  87
+				
  88
+				// If the actual CPU execution time of the node.js thread exceeded the threshold, terminate
  89
+				// the V8 process. Otherwise wait again while maintaining the current snapshot of the initial
  90
+				// time utilization. This mechanism results in termination of a runaway thread some time in the
  91
+				// (tripwireThreshold, 2 * tripwireThreshold) range of CPU utilization.
  92
+
  93
+				if (elapsedMs >= tripwireThreshold)
  94
+				{
  95
+					terminated = 1;
  96
+					V8::TerminateExecution();
  97
+				}
  98
+				else
  99
+				{
  100
+					skipTimeCapture = 1;
  101
+				}
  102
+			}
  103
+		}
  104
+	}
  105
+	
  106
+	pthread_exit(NULL);
  107
+}
  108
+
  109
+Handle<Value> resetTripwireCore()
  110
+{
  111
+    HandleScope scope;
  112
+
  113
+    if (0 == tripwireThread) 
  114
+    {
  115
+    	// This is the first call to resetTripwire. Perform lazy initialization.
  116
+    	// Create the worker thread.
  117
+
  118
+    	if (0 != pthread_create(&tripwireThread, NULL, tripwireWorker, NULL))
  119
+    	{
  120
+    		return ThrowException(Exception::Error(String::New("Unable to initialize a tripwire thread.")));
  121
+    	}
  122
+    }
  123
+    else 
  124
+    {
  125
+    	// Signal the already existing worker thread using the condition variable. 
  126
+    	// This will cause the worker thread to 
  127
+    	// reset the elapsed time timer and pick up the new tripwireThreshold value.
  128
+
  129
+    	pthread_mutex_lock(&tripwireMutex);
  130
+    	pthread_cond_signal(&tripwireCondition);
  131
+    	pthread_mutex_unlock(&tripwireMutex);
  132
+    }
  133
+
  134
+    return Undefined();
  135
+}
  136
+
  137
+void initCore() 
  138
+{
  139
+	tripwireThread = 0;
  140
+}

0 notes on commit e8acd8c

Please sign in to comment.
Something went wrong with that request. Please try again.