Description:
box uses user time
Commit status:
[Not Reviewed]
References:
Diff options:
Comments:
0 Commit comments
0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
r130:db5312fad511 - - 1 file changed: 26 inserted, 4 deleted
@@ -1,428 +1,450 | |||||
|
1 | /* |
|
1 | /* |
|
2 | This sandbox module is from [Fossil |
|
2 | This sandbox module is from [Fossil |
|
3 | grader](http://code.google.com/p/fossil-grader/). |
|
3 | grader](http://code.google.com/p/fossil-grader/). |
|
4 |
|
4 | ||
|
5 | This library is a modification from a program called trun, taken |
|
5 | This library is a modification from a program called trun, taken |
|
6 | from an unknown source. (FIX THIS) |
|
6 | from an unknown source. (FIX THIS) |
|
7 |
|
7 | ||
|
8 | When compiling with Mingw, add "-lpsapi" to link Windows'memory stat |
|
8 | When compiling with Mingw, add "-lpsapi" to link Windows'memory stat |
|
9 | library. |
|
9 | library. |
|
10 | */ |
|
10 | */ |
|
11 | #include <windows.h> |
|
11 | #include <windows.h> |
|
12 | #include <psapi.h> |
|
12 | #include <psapi.h> |
|
13 | #include <tlhelp32.h> |
|
13 | #include <tlhelp32.h> |
|
14 | #include <stdio.h> |
|
14 | #include <stdio.h> |
|
15 | #include "execute.h" |
|
15 | #include "execute.h" |
|
16 |
|
16 | ||
|
17 | #define INITIAL_WAIT_FOR_MEM_CHECK 100 |
|
17 | #define INITIAL_WAIT_FOR_MEM_CHECK 100 |
|
18 |
|
18 | ||
|
19 | /* |
|
19 | /* |
|
20 | ==How execute works== |
|
20 | ==How execute works== |
|
21 |
|
21 | ||
|
22 | ===Start up=== |
|
22 | ===Start up=== |
|
23 | Set up basic configurations: input file, output file |
|
23 | Set up basic configurations: input file, output file |
|
24 | into STARTUPINFO struct to be passed to CreateProcess. |
|
24 | into STARTUPINFO struct to be passed to CreateProcess. |
|
25 |
|
25 | ||
|
26 | Create a child process with CreateProcess. |
|
26 | Create a child process with CreateProcess. |
|
27 |
|
27 | ||
|
28 | ===Wait=== |
|
28 | ===Wait=== |
|
29 | Use WaitForSingleObject to wait. |
|
29 | Use WaitForSingleObject to wait. |
|
30 |
|
30 | ||
|
31 | ===Killing chile process=== |
|
31 | ===Killing chile process=== |
|
32 | This process is really involved, because (1) programs in |
|
32 | This process is really involved, because (1) programs in |
|
33 | DOS mode actually runs inside NTVDM so killing them |
|
33 | DOS mode actually runs inside NTVDM so killing them |
|
34 | requires to kill NTVDM, (2) something a program crashes |
|
34 | requires to kill NTVDM, (2) something a program crashes |
|
35 | NTVDM and a dialog box pops up, and we need to close |
|
35 | NTVDM and a dialog box pops up, and we need to close |
|
36 | that dialog box MANUALLY, and (3) for Win32 apps that crash, |
|
36 | that dialog box MANUALLY, and (3) for Win32 apps that crash, |
|
37 | some reporting service in Windows opens a dialog box, |
|
37 | some reporting service in Windows opens a dialog box, |
|
38 | and it has to be killed. |
|
38 | and it has to be killed. |
|
39 |
|
39 | ||
|
40 | Those extra steps are what's exactly done here: |
|
40 | Those extra steps are what's exactly done here: |
|
41 | 1. Kill the process if there's any |
|
41 | 1. Kill the process if there's any |
|
42 | 2. In case that there's no real process, find NTVDM |
|
42 | 2. In case that there's no real process, find NTVDM |
|
43 | and kill it (repeatedly until it's gone) |
|
43 | and kill it (repeatedly until it's gone) |
|
44 | 3. Check if NTVDM crashed and some warning dialog opens, |
|
44 | 3. Check if NTVDM crashed and some warning dialog opens, |
|
45 | if there's any, signal the user and wait. |
|
45 | if there's any, signal the user and wait. |
|
46 | 4. For real Win32 apps, find process "dwwin.exe" which |
|
46 | 4. For real Win32 apps, find process "dwwin.exe" which |
|
47 | represents an agent for reporting service and also |
|
47 | represents an agent for reporting service and also |
|
48 | opens a dialog. If finds it, kill it (repeatedly) |
|
48 | opens a dialog. If finds it, kill it (repeatedly) |
|
49 | until it's gone. |
|
49 | until it's gone. |
|
50 |
|
50 | ||
|
51 | Step 4. might be problematic --- dwwin.exe might not |
|
51 | Step 4. might be problematic --- dwwin.exe might not |
|
52 | be a universal process for error reporting services??? |
|
52 | be a universal process for error reporting services??? |
|
53 | */ |
|
53 | */ |
|
54 |
|
54 | ||
|
55 |
|
55 | ||
|
56 |
|
56 | ||
|
57 | /* |
|
57 | /* |
|
58 | These are routines that check NTVDM crash dialog. |
|
58 | These are routines that check NTVDM crash dialog. |
|
59 | It works by enumerating all window titles, and |
|
59 | It works by enumerating all window titles, and |
|
60 | checks for "16 bit" or something with ".exe" somewhere |
|
60 | checks for "16 bit" or something with ".exe" somewhere |
|
61 | and starts with "cmd.exe". |
|
61 | and starts with "cmd.exe". |
|
62 | */ |
|
62 | */ |
|
63 | bool NTVDMcrashed_found; |
|
63 | bool NTVDMcrashed_found; |
|
64 |
|
64 | ||
|
65 | /* this is a callback for window title enumeration */ |
|
65 | /* this is a callback for window title enumeration */ |
|
66 | BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) |
|
66 | BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) |
|
67 | { |
|
67 | { |
|
68 | char buffer[256]; |
|
68 | char buffer[256]; |
|
69 | GetWindowText(hWnd, buffer, 256); |
|
69 | GetWindowText(hWnd, buffer, 256); |
|
70 |
|
70 | ||
|
71 | if(strlen(buffer)!=0) { |
|
71 | if(strlen(buffer)!=0) { |
|
72 | if(strstr(buffer,"16 bit")!=0) { |
|
72 | if(strstr(buffer,"16 bit")!=0) { |
|
73 | NTVDMcrashed_found = true; |
|
73 | NTVDMcrashed_found = true; |
|
74 | } |
|
74 | } |
|
75 | if((strstr(buffer,".exe")!=0) && |
|
75 | if((strstr(buffer,".exe")!=0) && |
|
76 | (strstr(buffer,"cmd.exe")==buffer)) { |
|
76 | (strstr(buffer,"cmd.exe")==buffer)) { |
|
77 | NTVDMcrashed_found = true; |
|
77 | NTVDMcrashed_found = true; |
|
78 | printf("Title: %s\n",buffer); |
|
78 | printf("Title: %s\n",buffer); |
|
79 | } |
|
79 | } |
|
80 | } |
|
80 | } |
|
81 | return TRUE; |
|
81 | return TRUE; |
|
82 | } |
|
82 | } |
|
83 |
|
83 | ||
|
84 | bool check_ntvdm_dialog() |
|
84 | bool check_ntvdm_dialog() |
|
85 | { |
|
85 | { |
|
86 | NTVDMcrashed_found = false; |
|
86 | NTVDMcrashed_found = false; |
|
87 |
|
87 | ||
|
88 | FARPROC EnumProcInstance = MakeProcInstance((FARPROC)EnumWindowsProc, |
|
88 | FARPROC EnumProcInstance = MakeProcInstance((FARPROC)EnumWindowsProc, |
|
89 | AfxGetInstanceHandle()); |
|
89 | AfxGetInstanceHandle()); |
|
90 | EnumWindows((WNDENUMPROC)EnumProcInstance, (LPARAM)0); |
|
90 | EnumWindows((WNDENUMPROC)EnumProcInstance, (LPARAM)0); |
|
91 | FreeProcInstance(EnumProcInstance); |
|
91 | FreeProcInstance(EnumProcInstance); |
|
92 |
|
92 | ||
|
93 | return NTVDMcrashed_found; |
|
93 | return NTVDMcrashed_found; |
|
94 | } |
|
94 | } |
|
95 |
|
95 | ||
|
96 | DWORD get_process_id(char *pname) |
|
96 | DWORD get_process_id(char *pname) |
|
97 | { |
|
97 | { |
|
98 | HANDLE hProcessSnap; |
|
98 | HANDLE hProcessSnap; |
|
99 | HANDLE hProcess; |
|
99 | HANDLE hProcess; |
|
100 | PROCESSENTRY32 pe32; |
|
100 | PROCESSENTRY32 pe32; |
|
101 | DWORD dwPriorityClass; |
|
101 | DWORD dwPriorityClass; |
|
102 | DWORD pid=0; |
|
102 | DWORD pid=0; |
|
103 |
|
103 | ||
|
104 | hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); |
|
104 | hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); |
|
105 | if( hProcessSnap == INVALID_HANDLE_VALUE ) { |
|
105 | if( hProcessSnap == INVALID_HANDLE_VALUE ) { |
|
106 | return 0; |
|
106 | return 0; |
|
107 | } |
|
107 | } |
|
108 |
|
108 | ||
|
109 | pe32.dwSize = sizeof( PROCESSENTRY32 ); |
|
109 | pe32.dwSize = sizeof( PROCESSENTRY32 ); |
|
110 | if( !Process32First( hProcessSnap, &pe32 ) ) { |
|
110 | if( !Process32First( hProcessSnap, &pe32 ) ) { |
|
111 | CloseHandle( hProcessSnap ); |
|
111 | CloseHandle( hProcessSnap ); |
|
112 | return 0; |
|
112 | return 0; |
|
113 | } |
|
113 | } |
|
114 |
|
114 | ||
|
115 | do { |
|
115 | do { |
|
116 | if(strcasecmp(pe32.szExeFile ,pname)==0) |
|
116 | if(strcasecmp(pe32.szExeFile ,pname)==0) |
|
117 | pid = pe32.th32ProcessID; |
|
117 | pid = pe32.th32ProcessID; |
|
118 | } while( Process32Next( hProcessSnap, &pe32 ) ); |
|
118 | } while( Process32Next( hProcessSnap, &pe32 ) ); |
|
119 |
|
119 | ||
|
120 | CloseHandle( hProcessSnap ); |
|
120 | CloseHandle( hProcessSnap ); |
|
121 | return pid; |
|
121 | return pid; |
|
122 | } |
|
122 | } |
|
123 |
|
123 | ||
|
124 | DWORD get_ntvdm_pid() |
|
124 | DWORD get_ntvdm_pid() |
|
125 | { |
|
125 | { |
|
126 | return get_process_id("ntvdm.exe"); |
|
126 | return get_process_id("ntvdm.exe"); |
|
127 | } |
|
127 | } |
|
128 |
|
128 | ||
|
129 | void kill_error_report() |
|
129 | void kill_error_report() |
|
130 | { |
|
130 | { |
|
131 | DWORD pid; |
|
131 | DWORD pid; |
|
132 | do { |
|
132 | do { |
|
133 | if((pid = get_process_id("dwwin.exe"))!=0) { |
|
133 | if((pid = get_process_id("dwwin.exe"))!=0) { |
|
134 | fprintf(stderr," -- with error report (pid: %ld)\n",pid); |
|
134 | fprintf(stderr," -- with error report (pid: %ld)\n",pid); |
|
135 | HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid); |
|
135 | HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid); |
|
136 | if(hProcess!=NULL) { |
|
136 | if(hProcess!=NULL) { |
|
137 | TerminateProcess(hProcess, 0); |
|
137 | TerminateProcess(hProcess, 0); |
|
138 | Sleep(500); |
|
138 | Sleep(500); |
|
139 | while(get_process_id("dwwin.exe")==pid) { |
|
139 | while(get_process_id("dwwin.exe")==pid) { |
|
140 | fprintf(stderr,"wait for dwwin.exe to die...\n"); |
|
140 | fprintf(stderr,"wait for dwwin.exe to die...\n"); |
|
141 | Sleep(500); |
|
141 | Sleep(500); |
|
142 | } |
|
142 | } |
|
143 | } else |
|
143 | } else |
|
144 | fprintf(stderr,"do not have permission (%d)\n", |
|
144 | fprintf(stderr,"do not have permission (%d)\n", |
|
145 | GetLastError()); |
|
145 | GetLastError()); |
|
146 | } |
|
146 | } |
|
147 | } while(get_process_id("dwwin.exe")!=0); |
|
147 | } while(get_process_id("dwwin.exe")!=0); |
|
148 | } |
|
148 | } |
|
149 |
|
149 | ||
|
150 | void wait_dialog() |
|
150 | void wait_dialog() |
|
151 | { |
|
151 | { |
|
152 | kill_error_report(); |
|
152 | kill_error_report(); |
|
153 | if(check_ntvdm_dialog()) { |
|
153 | if(check_ntvdm_dialog()) { |
|
154 | fprintf(stderr,"Some dialog opens; please MANUALLY kill it."); |
|
154 | fprintf(stderr,"Some dialog opens; please MANUALLY kill it."); |
|
155 | fflush(stderr); |
|
155 | fflush(stderr); |
|
156 | do { |
|
156 | do { |
|
157 | Sleep(1000); |
|
157 | Sleep(1000); |
|
158 | } while(check_ntvdm_dialog()); |
|
158 | } while(check_ntvdm_dialog()); |
|
159 | fprintf(stderr,"... done\n"); |
|
159 | fprintf(stderr,"... done\n"); |
|
160 | } |
|
160 | } |
|
161 | } |
|
161 | } |
|
162 |
|
162 | ||
|
163 | void setstartupinfo(STARTUPINFO *si, char *inname, char *outname) |
|
163 | void setstartupinfo(STARTUPINFO *si, char *inname, char *outname) |
|
164 | { |
|
164 | { |
|
165 | SECURITY_ATTRIBUTES sa; |
|
165 | SECURITY_ATTRIBUTES sa; |
|
166 |
|
166 | ||
|
167 | ZeroMemory(&sa, sizeof(sa)); |
|
167 | ZeroMemory(&sa, sizeof(sa)); |
|
168 | sa.nLength = sizeof(SECURITY_ATTRIBUTES); |
|
168 | sa.nLength = sizeof(SECURITY_ATTRIBUTES); |
|
169 | sa.lpSecurityDescriptor = NULL; |
|
169 | sa.lpSecurityDescriptor = NULL; |
|
170 | sa.bInheritHandle = TRUE; |
|
170 | sa.bInheritHandle = TRUE; |
|
171 |
|
171 | ||
|
172 | si->dwFlags = STARTF_USESTDHANDLES; |
|
172 | si->dwFlags = STARTF_USESTDHANDLES; |
|
173 | if((inname!=0) && (strcmp(inname,"-")!=0)) { |
|
173 | if((inname!=0) && (strcmp(inname,"-")!=0)) { |
|
174 | si->hStdInput = CreateFile(inname, |
|
174 | si->hStdInput = CreateFile(inname, |
|
175 | FILE_READ_DATA, |
|
175 | FILE_READ_DATA, |
|
176 | FILE_SHARE_READ, |
|
176 | FILE_SHARE_READ, |
|
177 | &sa, |
|
177 | &sa, |
|
178 | OPEN_EXISTING, |
|
178 | OPEN_EXISTING, |
|
179 | FILE_ATTRIBUTE_NORMAL, |
|
179 | FILE_ATTRIBUTE_NORMAL, |
|
180 | NULL); |
|
180 | NULL); |
|
181 | } else |
|
181 | } else |
|
182 | si->hStdInput = NULL; |
|
182 | si->hStdInput = NULL; |
|
183 |
|
183 | ||
|
184 | if((outname!=0) && (strcmp(outname,"-")!=0)) { |
|
184 | if((outname!=0) && (strcmp(outname,"-")!=0)) { |
|
185 | si->hStdOutput = CreateFile(outname, |
|
185 | si->hStdOutput = CreateFile(outname, |
|
186 | FILE_WRITE_DATA, |
|
186 | FILE_WRITE_DATA, |
|
187 | FILE_SHARE_READ, |
|
187 | FILE_SHARE_READ, |
|
188 | &sa, |
|
188 | &sa, |
|
189 | CREATE_ALWAYS, |
|
189 | CREATE_ALWAYS, |
|
190 | FILE_ATTRIBUTE_NORMAL, |
|
190 | FILE_ATTRIBUTE_NORMAL, |
|
191 | NULL); |
|
191 | NULL); |
|
192 | } else |
|
192 | } else |
|
193 | si->hStdOutput = NULL; |
|
193 | si->hStdOutput = NULL; |
|
194 |
|
194 | ||
|
195 | si->hStdError = NULL; |
|
195 | si->hStdError = NULL; |
|
196 | } |
|
196 | } |
|
197 |
|
197 | ||
|
198 | // taken from http://msdn.microsoft.com/en-us/library/ms682050(VS.85).aspx |
|
198 | // taken from http://msdn.microsoft.com/en-us/library/ms682050(VS.85).aspx |
|
199 | void PrintMemoryInfo(DWORD processID) |
|
199 | void PrintMemoryInfo(DWORD processID) |
|
200 | { |
|
200 | { |
|
201 | HANDLE hProcess; |
|
201 | HANDLE hProcess; |
|
202 | PROCESS_MEMORY_COUNTERS pmc; |
|
202 | PROCESS_MEMORY_COUNTERS pmc; |
|
203 |
|
203 | ||
|
204 | // Print the process identifier. |
|
204 | // Print the process identifier. |
|
205 |
|
205 | ||
|
206 | printf("\nProcess ID: %u\n", processID); |
|
206 | printf("\nProcess ID: %u\n", processID); |
|
207 |
|
207 | ||
|
208 | // Print information about the memory usage of the process. |
|
208 | // Print information about the memory usage of the process. |
|
209 |
|
209 | ||
|
210 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | |
|
210 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | |
|
211 | PROCESS_VM_READ, |
|
211 | PROCESS_VM_READ, |
|
212 | FALSE,processID); |
|
212 | FALSE,processID); |
|
213 | if(hProcess == NULL) |
|
213 | if(hProcess == NULL) |
|
214 | return; |
|
214 | return; |
|
215 |
|
215 | ||
|
216 | if(GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) { |
|
216 | if(GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) { |
|
217 | printf("\tPageFaultCount: %d\n",pmc.PageFaultCount); |
|
217 | printf("\tPageFaultCount: %d\n",pmc.PageFaultCount); |
|
218 | printf("\tPeakWorkingSetSize: %d\n", |
|
218 | printf("\tPeakWorkingSetSize: %d\n", |
|
219 | pmc.PeakWorkingSetSize); |
|
219 | pmc.PeakWorkingSetSize); |
|
220 | printf("\tWorkingSetSize: %d\n",pmc.WorkingSetSize); |
|
220 | printf("\tWorkingSetSize: %d\n",pmc.WorkingSetSize); |
|
221 | printf("\tQuotaPeakPagedPoolUsage: %d\n", |
|
221 | printf("\tQuotaPeakPagedPoolUsage: %d\n", |
|
222 | pmc.QuotaPeakPagedPoolUsage); |
|
222 | pmc.QuotaPeakPagedPoolUsage); |
|
223 | printf("\tQuotaPagedPoolUsage: %d\n", |
|
223 | printf("\tQuotaPagedPoolUsage: %d\n", |
|
224 | pmc.QuotaPagedPoolUsage); |
|
224 | pmc.QuotaPagedPoolUsage); |
|
225 | printf("\tQuotaPeakNonPagedPoolUsage: %d\n", |
|
225 | printf("\tQuotaPeakNonPagedPoolUsage: %d\n", |
|
226 | pmc.QuotaPeakNonPagedPoolUsage); |
|
226 | pmc.QuotaPeakNonPagedPoolUsage); |
|
227 | printf("\tQuotaNonPagedPoolUsage: %d\n", |
|
227 | printf("\tQuotaNonPagedPoolUsage: %d\n", |
|
228 | pmc.QuotaNonPagedPoolUsage); |
|
228 | pmc.QuotaNonPagedPoolUsage); |
|
229 | printf("\tPagefileUsage: %d\n",pmc.PagefileUsage); |
|
229 | printf("\tPagefileUsage: %d\n",pmc.PagefileUsage); |
|
230 | printf("\tPeakPagefileUsage: %d\n", |
|
230 | printf("\tPeakPagefileUsage: %d\n", |
|
231 | pmc.PeakPagefileUsage); |
|
231 | pmc.PeakPagefileUsage); |
|
232 | } |
|
232 | } |
|
233 | CloseHandle( hProcess ); |
|
233 | CloseHandle( hProcess ); |
|
234 | } |
|
234 | } |
|
235 |
|
235 | ||
|
236 | int check_memory_usage(DWORD pid, int max_mem, int *actual_usage) { |
|
236 | int check_memory_usage(DWORD pid, int max_mem, int *actual_usage) { |
|
237 | // modified from http://msdn.microsoft.com/en-us/library/ms682050(VS.85).aspx |
|
237 | // modified from http://msdn.microsoft.com/en-us/library/ms682050(VS.85).aspx |
|
238 | //PrintMemoryInfo(pid); |
|
238 | //PrintMemoryInfo(pid); |
|
239 | HANDLE hProcess; |
|
239 | HANDLE hProcess; |
|
240 | PROCESS_MEMORY_COUNTERS pmc; |
|
240 | PROCESS_MEMORY_COUNTERS pmc; |
|
241 |
|
241 | ||
|
242 | if((max_mem==0) || (pid==0)) |
|
242 | if((max_mem==0) || (pid==0)) |
|
243 | return 1; |
|
243 | return 1; |
|
244 |
|
244 | ||
|
245 | if(pid == get_ntvdm_pid()) { |
|
245 | if(pid == get_ntvdm_pid()) { |
|
246 | fprintf(stderr,"ntvdm: ignored\n"); |
|
246 | fprintf(stderr,"ntvdm: ignored\n"); |
|
247 | return 1; |
|
247 | return 1; |
|
248 | } |
|
248 | } |
|
249 |
|
249 | ||
|
250 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | |
|
250 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | |
|
251 | PROCESS_VM_READ, |
|
251 | PROCESS_VM_READ, |
|
252 | FALSE, pid); |
|
252 | FALSE, pid); |
|
253 | if(hProcess == NULL) |
|
253 | if(hProcess == NULL) |
|
254 | return 1; |
|
254 | return 1; |
|
255 |
|
255 | ||
|
256 | int max_mem_usage = 0; |
|
256 | int max_mem_usage = 0; |
|
257 | if(GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) { |
|
257 | if(GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) { |
|
258 | max_mem_usage = pmc.PeakWorkingSetSize; |
|
258 | max_mem_usage = pmc.PeakWorkingSetSize; |
|
259 | if(pmc.PeakPagefileUsage > max_mem_usage) |
|
259 | if(pmc.PeakPagefileUsage > max_mem_usage) |
|
260 | max_mem_usage = pmc.PeakPagefileUsage; |
|
260 | max_mem_usage = pmc.PeakPagefileUsage; |
|
261 | } |
|
261 | } |
|
262 | CloseHandle(hProcess); |
|
262 | CloseHandle(hProcess); |
|
263 | if(actual_usage != NULL) |
|
263 | if(actual_usage != NULL) |
|
264 | (*actual_usage) = max_mem_usage; |
|
264 | (*actual_usage) = max_mem_usage; |
|
265 | return (max_mem_usage <= max_mem); |
|
265 | return (max_mem_usage <= max_mem); |
|
266 | } |
|
266 | } |
|
267 |
|
267 | ||
|
268 | void report_stat(double time_used, int memory_used) |
|
268 | void report_stat(double time_used, int memory_used) |
|
269 | { |
|
269 | { |
|
270 | fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dm\n", |
|
270 | fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dm\n", |
|
271 | time_used, |
|
271 | time_used, |
|
272 | time_used, (double)0, |
|
272 | time_used, (double)0, |
|
273 | memory_used); |
|
273 | memory_used); |
|
274 | } |
|
274 | } |
|
275 |
|
275 | ||
|
276 | double get_process_time_usage(HANDLE hProcess) |
|
276 | double get_process_time_usage(HANDLE hProcess) |
|
277 | { |
|
277 | { |
|
278 | FILETIME creation_time; |
|
278 | FILETIME creation_time; |
|
279 | FILETIME exit_time; |
|
279 | FILETIME exit_time; |
|
280 | FILETIME kernel_time; |
|
280 | FILETIME kernel_time; |
|
281 | FILETIME user_time; |
|
281 | FILETIME user_time; |
|
282 | GetProcessTimes(hProcess, |
|
282 | GetProcessTimes(hProcess, |
|
283 | &creation_time, |
|
283 | &creation_time, |
|
284 | &exit_time, |
|
284 | &exit_time, |
|
285 | &kernel_time, |
|
285 | &kernel_time, |
|
286 | &user_time); |
|
286 | &user_time); |
|
287 |
|
287 | ||
|
288 | SYSTEMTIME sys_kernel_time; |
|
288 | SYSTEMTIME sys_kernel_time; |
|
289 | SYSTEMTIME sys_user_time; |
|
289 | SYSTEMTIME sys_user_time; |
|
290 | FileTimeToSystemTime(&kernel_time, &sys_kernel_time); |
|
290 | FileTimeToSystemTime(&kernel_time, &sys_kernel_time); |
|
291 | FileTimeToSystemTime(&user_time, &sys_user_time); |
|
291 | FileTimeToSystemTime(&user_time, &sys_user_time); |
|
292 |
|
292 | ||
|
293 | double time_used = |
|
293 | double time_used = |
|
294 | ((sys_kernel_time.wSecond + sys_kernel_time.wMilliseconds/1000.0) + |
|
294 | ((sys_kernel_time.wSecond + sys_kernel_time.wMilliseconds/1000.0) + |
|
295 | (sys_user_time.wSecond + sys_user_time.wMilliseconds/1000.0)); |
|
295 | (sys_user_time.wSecond + sys_user_time.wMilliseconds/1000.0)); |
|
296 | return time_used; |
|
296 | return time_used; |
|
297 | } |
|
297 | } |
|
298 |
|
298 | ||
|
299 | int execute(char *exname, char *inname, char *outname, double t, int max_mem) |
|
299 | int execute(char *exname, char *inname, char *outname, double t, int max_mem) |
|
300 | { |
|
300 | { |
|
301 | STARTUPINFO si; |
|
301 | STARTUPINFO si; |
|
302 | PROCESS_INFORMATION pi; |
|
302 | PROCESS_INFORMATION pi; |
|
303 | int ifsuccess = EXE_RESULT_OK; |
|
303 | int ifsuccess = EXE_RESULT_OK; |
|
304 |
|
304 | ||
|
305 | ZeroMemory(&si, sizeof(si)); |
|
305 | ZeroMemory(&si, sizeof(si)); |
|
306 | si.cb = sizeof(si); |
|
306 | si.cb = sizeof(si); |
|
307 | ZeroMemory(&pi, sizeof(pi)); |
|
307 | ZeroMemory(&pi, sizeof(pi)); |
|
308 |
|
308 | ||
|
309 | setstartupinfo(&si, inname, outname); |
|
309 | setstartupinfo(&si, inname, outname); |
|
310 |
|
310 | ||
|
311 | if(!CreateProcess( NULL, // No module name (use command line). |
|
311 | if(!CreateProcess( NULL, // No module name (use command line). |
|
312 | TEXT(exname), // Command line. |
|
312 | TEXT(exname), // Command line. |
|
313 | NULL, // Process handle not inheritable. |
|
313 | NULL, // Process handle not inheritable. |
|
314 | NULL, // Thread handle not inheritable. |
|
314 | NULL, // Thread handle not inheritable. |
|
315 | TRUE, // Set handle inheritance to FALSE. |
|
315 | TRUE, // Set handle inheritance to FALSE. |
|
316 | 0, // No creation flags. |
|
316 | 0, // No creation flags. |
|
317 | NULL, // Use parent's environment block. |
|
317 | NULL, // Use parent's environment block. |
|
318 | NULL, // Use parent's starting directory. |
|
318 | NULL, // Use parent's starting directory. |
|
319 | &si, // Pointer to STARTUPINFO structure. |
|
319 | &si, // Pointer to STARTUPINFO structure. |
|
320 | &pi)) // Pointer to PROCESS_INFORMATION structure. |
|
320 | &pi)) // Pointer to PROCESS_INFORMATION structure. |
|
321 | { |
|
321 | { |
|
322 | //printf( "CreateProcess failed (%d).\n", GetLastError() ); |
|
322 | //printf( "CreateProcess failed (%d).\n", GetLastError() ); |
|
323 | fprintf(stderr, "Process creation error.\n"); |
|
323 | fprintf(stderr, "Process creation error.\n"); |
|
324 | report_stat(0,0); |
|
324 | report_stat(0,0); |
|
325 | return EXE_RESULT_ERROR; |
|
325 | return EXE_RESULT_ERROR; |
|
326 | } |
|
326 | } |
|
327 | //fprintf(stderr,"Process ID: %ld\n",pi.dwProcessId); |
|
327 | //fprintf(stderr,"Process ID: %ld\n",pi.dwProcessId); |
|
328 | //fprintf(stderr,"time limit = %d\n",t); |
|
328 | //fprintf(stderr,"time limit = %d\n",t); |
|
329 |
|
329 | ||
|
330 | // checking memory usage |
|
330 | // checking memory usage |
|
331 | // wait 0.1 sec before checking mem usage |
|
331 | // wait 0.1 sec before checking mem usage |
|
332 |
|
332 | ||
|
333 | SetProcessWorkingSetSize(pi.hProcess, |
|
333 | SetProcessWorkingSetSize(pi.hProcess, |
|
334 | 1, |
|
334 | 1, |
|
335 | max_mem); |
|
335 | max_mem); |
|
336 | int actual_memory_usage = 0; |
|
336 | int actual_memory_usage = 0; |
|
337 |
|
337 | ||
|
338 | Sleep(INITIAL_WAIT_FOR_MEM_CHECK); |
|
338 | Sleep(INITIAL_WAIT_FOR_MEM_CHECK); |
|
339 | if(!check_memory_usage(pi.dwProcessId,max_mem,&actual_memory_usage)) { |
|
339 | if(!check_memory_usage(pi.dwProcessId,max_mem,&actual_memory_usage)) { |
|
340 | // using too much memory |
|
340 | // using too much memory |
|
341 | fprintf(stderr,"Memory limit exceeded.\n"); |
|
341 | fprintf(stderr,"Memory limit exceeded.\n"); |
|
342 | //PrintMemoryInfo(pi.dwProcessId); |
|
342 | //PrintMemoryInfo(pi.dwProcessId); |
|
343 | ifsuccess = EXE_RESULT_MEMORY; |
|
343 | ifsuccess = EXE_RESULT_MEMORY; |
|
344 | } |
|
344 | } |
|
345 |
|
345 | ||
|
346 | - if((ifsuccess == EXE_RESULT_MEMORY) || |
|
346 | + //printf("PID: %d\n", pi.dwProcessId); |
|
347 | - (WaitForSingleObject(pi.hProcess, |
|
347 | + |
|
348 | - (int)(t*1000) + 1 |
|
348 | + if(ifsuccess != EXE_RESULT_MEMORY) { |
|
349 | - - INITIAL_WAIT_FOR_MEM_CHECK)==WAIT_TIMEOUT)) { |
|
349 | + int based_time = (int)(t*1000) + 1 - INITIAL_WAIT_FOR_MEM_CHECK; |
|
|
350 | + bool major_timed_out = (WaitForSingleObject(pi.hProcess, | ||
|
|
351 | + based_time)==WAIT_TIMEOUT); | ||
|
|
352 | + if(major_timed_out) { | ||
|
|
353 | + // wait some more for user time. | ||
|
|
354 | + double time_used = get_process_time_usage(pi.hProcess); | ||
|
|
355 | + while(time_used <= t) { | ||
|
|
356 | + int iter_time = 100; | ||
|
|
357 | + if(t - time_used < 200) | ||
|
|
358 | + iter_time = 20; | ||
|
|
359 | + bool iter_timed_out = (WaitForSingleObject(pi.hProcess, | ||
|
|
360 | + iter_time)==WAIT_TIMEOUT); | ||
|
|
361 | + if(!iter_timed_out) | ||
|
|
362 | + break; | ||
|
|
363 | + | ||
|
|
364 | + time_used = get_process_time_usage(pi.hProcess); | ||
|
|
365 | + //printf("%lf\n",time_used); | ||
|
|
366 | + } | ||
|
|
367 | + ifsuccess = EXE_RESULT_TIMEOUT; | ||
|
|
368 | + } | ||
|
|
369 | + } | ||
|
|
370 | + | ||
|
|
371 | + if((ifsuccess == EXE_RESULT_MEMORY) || (ifsuccess == EXE_RESULT_TIMEOUT)) { | ||
|
350 | // Kill process, because (1) it used too much memory, or (2) time limit |
|
372 | // Kill process, because (1) it used too much memory, or (2) time limit |
|
351 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId); |
|
373 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId); |
|
352 |
|
374 | ||
|
353 | if(ifsuccess != EXE_RESULT_MEMORY) |
|
375 | if(ifsuccess != EXE_RESULT_MEMORY) |
|
354 | fprintf(stderr,"Time limit exceeded.\n"); |
|
376 | fprintf(stderr,"Time limit exceeded.\n"); |
|
355 | if(hProcess != NULL) { |
|
377 | if(hProcess != NULL) { |
|
356 | fprintf(stderr,"killing pid: %ld\n",pi.dwProcessId); |
|
378 | fprintf(stderr,"killing pid: %ld\n",pi.dwProcessId); |
|
357 | TerminateProcess(hProcess, 0); |
|
379 | TerminateProcess(hProcess, 0); |
|
358 | wait_dialog(); |
|
380 | wait_dialog(); |
|
359 | } else { |
|
381 | } else { |
|
360 | DWORD dwNtvdmId = get_ntvdm_pid(); |
|
382 | DWORD dwNtvdmId = get_ntvdm_pid(); |
|
361 | fprintf(stderr,"killing (ntvdm) pid: %ld\n",dwNtvdmId); |
|
383 | fprintf(stderr,"killing (ntvdm) pid: %ld\n",dwNtvdmId); |
|
362 | if(dwNtvdmId!=0) { |
|
384 | if(dwNtvdmId!=0) { |
|
363 | hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwNtvdmId); |
|
385 | hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwNtvdmId); |
|
364 | TerminateProcess(hProcess, 0); |
|
386 | TerminateProcess(hProcess, 0); |
|
365 | } else { |
|
387 | } else { |
|
366 | fprintf(stderr,"killing process error\n"); |
|
388 | fprintf(stderr,"killing process error\n"); |
|
367 | } |
|
389 | } |
|
368 |
|
390 | ||
|
369 | if(get_ntvdm_pid()!=0) { |
|
391 | if(get_ntvdm_pid()!=0) { |
|
370 | fprintf(stderr,"killing error, ntvdm.exe still remains;"); |
|
392 | fprintf(stderr,"killing error, ntvdm.exe still remains;"); |
|
371 | fprintf(stderr,"please MANUALLY kill it."); |
|
393 | fprintf(stderr,"please MANUALLY kill it."); |
|
372 | fflush(stderr); |
|
394 | fflush(stderr); |
|
373 | do { |
|
395 | do { |
|
374 | Sleep(1000); |
|
396 | Sleep(1000); |
|
375 | } while(get_ntvdm_pid()!=0); |
|
397 | } while(get_ntvdm_pid()!=0); |
|
376 | fprintf(stderr,"... done\n"); |
|
398 | fprintf(stderr,"... done\n"); |
|
377 | wait_dialog(); |
|
399 | wait_dialog(); |
|
378 | } |
|
400 | } |
|
379 | } |
|
401 | } |
|
380 | if(ifsuccess != EXE_RESULT_MEMORY) |
|
402 | if(ifsuccess != EXE_RESULT_MEMORY) |
|
381 | ifsuccess = EXE_RESULT_TIMEOUT; |
|
403 | ifsuccess = EXE_RESULT_TIMEOUT; |
|
382 | } |
|
404 | } |
|
383 |
|
405 | ||
|
384 | // check memory after terminated |
|
406 | // check memory after terminated |
|
385 | if((ifsuccess==EXE_RESULT_OK) && |
|
407 | if((ifsuccess==EXE_RESULT_OK) && |
|
386 | (!check_memory_usage(pi.dwProcessId,max_mem, &actual_memory_usage))) { |
|
408 | (!check_memory_usage(pi.dwProcessId,max_mem, &actual_memory_usage))) { |
|
387 | // using too much memory |
|
409 | // using too much memory |
|
388 | ifsuccess = EXE_RESULT_MEMORY; |
|
410 | ifsuccess = EXE_RESULT_MEMORY; |
|
389 | } |
|
411 | } |
|
390 |
|
412 | ||
|
391 | // check return code |
|
413 | // check return code |
|
392 | if(ifsuccess==EXE_RESULT_OK) { |
|
414 | if(ifsuccess==EXE_RESULT_OK) { |
|
393 | DWORD exitcode; |
|
415 | DWORD exitcode; |
|
394 | GetExitCodeProcess(pi.hProcess, &exitcode); |
|
416 | GetExitCodeProcess(pi.hProcess, &exitcode); |
|
395 | if(exitcode!=0) { |
|
417 | if(exitcode!=0) { |
|
396 | fprintf(stderr,"Exit status %d.\n", (int)exitcode); |
|
418 | fprintf(stderr,"Exit status %d.\n", (int)exitcode); |
|
397 | ifsuccess = EXE_RESULT_ERROR; |
|
419 | ifsuccess = EXE_RESULT_ERROR; |
|
398 | } |
|
420 | } |
|
399 | } |
|
421 | } |
|
400 |
|
422 | ||
|
401 | wait_dialog(); |
|
423 | wait_dialog(); |
|
402 |
|
424 | ||
|
403 | if(si.hStdInput!=NULL) |
|
425 | if(si.hStdInput!=NULL) |
|
404 | CloseHandle(si.hStdInput); |
|
426 | CloseHandle(si.hStdInput); |
|
405 | if(si.hStdOutput!=NULL) |
|
427 | if(si.hStdOutput!=NULL) |
|
406 | CloseHandle(si.hStdOutput); |
|
428 | CloseHandle(si.hStdOutput); |
|
407 |
|
429 | ||
|
408 | if(ifsuccess==EXE_RESULT_OK) |
|
430 | if(ifsuccess==EXE_RESULT_OK) |
|
409 | fprintf(stderr,"OK\n"); |
|
431 | fprintf(stderr,"OK\n"); |
|
410 | else if(ifsuccess==EXE_RESULT_TIMEOUT) |
|
432 | else if(ifsuccess==EXE_RESULT_TIMEOUT) |
|
411 | fprintf(stderr,"Time limit exceeded.\n"); |
|
433 | fprintf(stderr,"Time limit exceeded.\n"); |
|
412 | else if(ifsuccess==EXE_RESULT_MEMORY) |
|
434 | else if(ifsuccess==EXE_RESULT_MEMORY) |
|
413 | fprintf(stderr,"Memory limit exceeded.\n"); |
|
435 | fprintf(stderr,"Memory limit exceeded.\n"); |
|
414 |
|
436 | ||
|
415 | double actual_time_usage = get_process_time_usage(pi.hProcess); |
|
437 | double actual_time_usage = get_process_time_usage(pi.hProcess); |
|
416 | /* |
|
438 | /* |
|
417 | if(ifsuccess==EXE_RESULT_TIMEOUT) |
|
439 | if(ifsuccess==EXE_RESULT_TIMEOUT) |
|
418 | actual_time_usage = t+1; |
|
440 | actual_time_usage = t+1; |
|
419 | else |
|
441 | else |
|
420 | actual_time_usage = t; |
|
442 | actual_time_usage = t; |
|
421 | */ |
|
443 | */ |
|
422 |
|
444 | ||
|
423 | report_stat(actual_time_usage, |
|
445 | report_stat(actual_time_usage, |
|
424 | (actual_memory_usage + 1023)/1024); |
|
446 | (actual_memory_usage + 1023)/1024); |
|
425 |
|
447 | ||
|
426 | return ifsuccess; |
|
448 | return ifsuccess; |
|
427 | } |
|
449 | } |
|
428 |
|
450 |
You need to be logged in to leave comments.
Login now