-
Notifications
You must be signed in to change notification settings - Fork 5
/
judge.py
358 lines (315 loc) · 13.2 KB
/
judge.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# # -*- coding: utf-8 -*-
import re,os,subprocess,signal,platform,sys,resource,time
import MySQLdb,psutil
#variables initialization
p = None
result = None
rc = None
sign = {
1: "SIGHUP", 2: "SIGINT", 3: "SIGQUIT", 4:"SIGILL",
5: "SIGTRAP", 6: "SIGABRT", 7: "SIGBUS", 8:"SIGFPE",
9: "SIGKILL", 10: "SIGUSR1", 11: "SIGSEGV", 12:"SIGUSR2",
13: "SIGPIPE", 14: "SIGALRM", 15: "SIGTERM", 16:"SIGSTKFLT",
17: "SIGCHLD", 18: "SIGCONT", 19: "SIGSTOP", 20:"SIGTSTP",
21: "SIGTTIN", 22: "SIGTTOU", 23: "SIGURG", 24:"SIGXCPU",
25: "SIGXFSZ", 26: "SIGVTALRM", 27: "SIGPROF", 28:"SIGWINCH",
29: "SIGIO", 30: "SIGPWR", 31: "SIGSYS", 3334:"SIGRTMIN"
}
#gcc and g++ : turn off debugging and optimization level2 -O2 -fomit-frame-pointer
#rhino and php : -f filename
#java : -g:none : no debugging info , -Xlint: enable warnings , -d :directory where to put class files
langDict = {
"C" : {"extension":"c", "system":"find /usr/bin/ -name gcc","compile":"gcc [path]/[codefilename].c -O2 -fomit-frame-pointer -o [path]/[codefilename]","execute":"[path]/[exename]"},
"C++": {"extension": "cpp", "system": "find /usr/bin/ -name g++","compile": "g++ [path]/[codefilename].cpp -O2 -fomit-frame-pointer -o [path]/[codefilename]", "execute":"[path]/[exename]"},
"C#" : {"extension": "cs", "system":"find /usr/bin/ -name gmcs","compile":"gmcs [path]/[codefilename].cs", "execute":"mono [path]/[exename].exe"},
"Java" : {"extension" : "java", "system":"find /usr/bin/ -name javac","compile":"javac -g:none -Xlint -d [path] [path]/[codefilename].java", "execute":"java -classpath [path] [exename]"},
"Pascal": {"extension":"pas", "system":"find /usr/bin/ -name fpc","compile":"fpc [path]/[codefilename].pas","execute":"[path]/[exename]"},
"Haskell":{"extension":"hs","system":"find /usr/bin/ -name ghc","compile":"ghc [path]/[codefilename].hs -o [path]/[codefilename]","execute":"[path]/[exename]"},
"JavaScript": {"extension":"js", "system": "find /usr/bin/ -name rhino", "execute":"rhino -f [path]/[exename].js"},
"Perl": {"extension":"pl", "system":"find /usr/bin/ -name perl","execute":"perl [path]/[exename].pl"},
"Pike": {"extension":"pike", "system":"find /usr/bin/ -name pike","execute":"pike [path]/[exename].pike"},
"PHP": {"extension":"php", "system":"find /usr/bin/ -name php","execute":"php -f [path]/[exename].php"},
"Python2.7": {"extension":"py", "system":"find /usr/bin/ -name python2","execute":"python2 [path]/[exename].py"},
"Python3": {"extension":"py", "system":"find /usr/bin/ -name python3","execute":"python3 [path]/[exename].py"},
"Ruby": {"extension":"rb", "system":"find /usr/bin/ -name ruby","execute":"ruby [path]/[exename].rb"},
"AWK": {"extension": "awk", "system":"find /usr/bin/ -name awk","execute":"awk -f [path]/[exename].awk"},
"Bash": {"extension": "sh", "system":"find /bin/ -name bash","execute":"bash [path]/[exename].sh"},
"Brain" : {"extension": "bf", "system":"find /usr/bin/ -name bf","execute":"bf [path]/[exename].bf"},
"Text": {"extension":"txt"}
}
rid = 0
pid = 0
memory = 0
access = None
submit_time = None
exec_time = None
username = None
path = None
codefilename = None
ext = None
langdB = None
Dlangs = []
soft_limit=1 #soft limit is the current limit, and may be lowered or raised by a process over time
hard_limit=2 #hard limit can be lowered to any value greater than the soft limit, but not raised
cpu_limit=20 #percentage of CPU usage(20%)
mem_limit = 1024000000 #in bytes : 256MB
proc_limit = 0 #number of processes
file_limit = 200000 # max file size generated
as_limit = 256000000 #max area of address space
#insert judged submissions into submissions table
def connect_db_judged():
global exec_time,memory
try:
db = MySQLdb.connect("localhost","root","root","compileone")
cursor = db.cursor()
if(exec_time == None):
exec_time = 0.0;
sql_ins = "INSERT INTO submissions VALUES('"+codefilename+"','"+username+"','"+langdB+"','"+ext+"','"+path+"','"+result+"','"+str(exec_time)+"','"+str(memory)+"','"+access+"','"+str(submit_time)+"',"+str(rid)+","+str(pid)+")"
sql_del = "DELETE FROM queue WHERE codefilename='"+codefilename+"'"
print sql_ins
print sql_del
cursor.execute(sql_ins)
cursor.execute(sql_del)
db.commit()
except Exception as e:
print e
db.rollback()
else:
# disconnect from server
db.close()
# Systems Check for languages
def system_check():
global Dlangs
for lang in langDict:
if(lang != "Text" and os.popen(langDict[lang]["system"]).read() != ""): #os.popen() opens a pipe to the command
Dlangs.append(lang);
# Perform system checks
def platform_check():
if(platform.system() != 'Linux'):
print("Error : Platform Incompatible script\n")
print("This script can run on Linux platform only")
sys.exit(0);
# clear screen and Print Header
def print_header():
exit_code = os.system("clear")
print("\nCodeshare Online Judge\n");
print "**********************************"
print "Languages Supported on this System:"
for i in range(len(Dlangs)):
print Dlangs[i],",",
print "\n"
print "**********************************"
# Obtain lock
def obtain_lock():
if(os.path.exists("lock.txt")):
print("Error : Could not obtain lock on Online Judge Script\n")
print("This problem usually occurs if : \n")
print("1) You are trying to run two instances of this script on the same machine at the same time.\n")
print("2) Improper termination the last time this was run, or an error in the script itself\n")
print("solution : shut down all instances of this script, manually delete the 'lock.txt' file (in the same directory) and restart a single instance of it.\n");
sys.exit(1);
else:
lock = open("lock.txt","w");
print("Obtained lock on Online Judge Script\n");
def signal_handler(signum,frame):
global p,result
print 'Signal handler called with signal',signum
result = "Time Limit Exceeded"
p.terminate()
print 'Time out'
#File Read/Write
def file_read(filename):
if not os.path.exists(filename):
return "";
f = open(filename,"r")
data = f.read()
f.close()
return data.replace("\r","") #replace extra \r befor \n
def file_write(filename,data):
f = open(filename,"w")
f.write(data.replace("\r",""))
f.close()
#Security : set resources limit on subprocess creation
def security():
if(langdB == "Java" or langdB == "C#"):
proc_limit = 300 #265
else:
proc_limit = 0
pid = os.getpid()
#ps = psutil.Process(pid)
#ps.set_nice(cpu_limit)
resource.setrlimit(resource.RLIMIT_CPU,(soft_limit,hard_limit))
resource.setrlimit(resource.RLIMIT_NPROC,(proc_limit,proc_limit))
resource.setrlimit(resource.RLIMIT_RSS,(mem_limit,mem_limit))
resource.setrlimit(resource.RLIMIT_FSIZE,(file_limit,file_limit))
#resource.setrlimit(resource.RLIMIT_AS,(as_limit,as_limit))
#Compilation
def compile():
global result,codefilename,path,ext
if (langDict[langdB]["extension"] == ext):
cmd = langDict[langdB]["compile"]
cmd = cmd.replace("[codefilename]",codefilename)
cmd = cmd.replace("[path]",path)
cmd = cmd.split(' ')
print cmd
path_stderr = "./env/"+codefilename+"/stderr.txt";
sp = subprocess.Popen(cmd,stderr = open(path_stderr,"w"),shell=False)
sp.communicate()
#print path+"/"+codefilename
if langdB == "Java":
if not os.path.exists(path+"/Main.class"):
result = "Compilation Error"
elif langdB == 'C#':
if not os.path.exists(path+"/"+codefilename+".exe"):
result = "Compilation Error"
else:
if not os.path.exists(path+"/"+codefilename):
result = "Compilation Error"
else:
result = "Invalid File"
#Execution
def execute():
global p,rc,langDict,result,pid,exec_time,memory
print "hello"
if (langDict[langdB]["extension"] == ext):
cmd = langDict[langdB]["execute"]
if(langdB == "Java"):
cmd = cmd.replace("[exename]","Main")
else:
cmd = cmd.replace("[exename]",codefilename)
cmd = cmd.replace("[path]",path)
cmd = cmd.split(' ')
print cmd
#timelimit = 100
#signal.signal(signal.SIGALRM,signal_handler) #set the handler for SIGALRM signal
#signal.alarm(timelimit) #set the alarm
stime = time.time()
path_stdout = "./env/"+codefilename+"/stdout.txt";
path_stderr = "./env/"+codefilename+"/stderr.txt";
path_stdin = "./env/"+codefilename+"/stdin.txt";
p =subprocess.Popen(cmd,stdin = open(path_stdin,"r"),stdout = open(path_stdout,"w"),stderr = open(path_stderr,"w") ,shell=False,preexec_fn = security) #process creation pipe with stdin,stdout,stderror not through shell style command(string)
p.wait() #interacts with child process
memory = (resource.getrusage(resource.RUSAGE_CHILDREN).ru_maxrss)/1000.0
etime = time.time()
exec_time = (etime - stime)/1000.0
exec_time = round(exec_time,4)
rc = p.returncode #exit code of child process
if( abs(rc) == 9):
result = "Time Limit Exceeded"
pid = p.pid
print rc
#temp = os.waitpid(p.pid,0)[1]
#print temp
#signal.alarm(0) #release the alarm
#os.system("rm lock.txt")
else:
result = "Invalid File"
def compare(a,b):
global result
d1 = file_read(a)
d2 = file_read(b)
if(d1 == d2):
result = "Accepted"
elif(re.sub(r"\s","",d1) == re.sub(r"\s","",d2)): #replace all whitespace(regular expression "\s") with ""
result = "Presentation Error"
else:
result = "Wrong Answer"
def check_result():
print "bye"
global result,rc
if(result == None):
rc = abs(rc)
if(rc == 0):
result = "Success"
elif(rc <= 34 and rc > 0):
result = "Runtime Error (" + sign[rc] +")"
else:
result = "NZEC"
if(ext == "txt"):
result = "Success"
def judge():
global result,codefilename,username,langdB,ext,path,soft_limit,hard_limit,access,submit_time
print codefilename,username,langdB,ext,path,hard_limit,access,submit_time
#compile only for c,c++,java,c#,pascal
if ext not in ["awk","py","js","pl","php","rb","pike","sh","bf","txt"]:
compile()
#increase time limit for slow languages
if ext in ["hs","py","rb"]:
soft_limit *= 3
hard_limit *= 3
if ext in ["cs","java","js"]:
soft_limit *= 2
hard_limit *= 2
print "hi"
#execute for all lang except text
if(result == None) and ext != "txt":
execute()
check_result()
print result
print exec_time
connect_db_judged()
result = None
#Connect to Database
def connect_mysql():
global codefilename,username,langdB,ext,path,soft_limit,hard_limit,access,submit_time
try:
# Open database connection
db = MySQLdb.connect("localhost","root","root","compileone")
# prepare a cursor object using cursor() method
cursor1 = db.cursor()
cursor2 = db.cursor()
# execute SQL query using execute() method.
sql = "select count(*) from queue"
cursor1.execute(sql)
# Fetch a single row using fetchone() method.
while(True):
print "start -------------------"
data = cursor1.fetchone()
if(data != None):
data = int(data[0])
if(data == None):
break;
qry = "select * from queue"
try:
cursor2.execute(qry)
rs = cursor2.fetchall()
for row in rs:
codefilename = str(row[0])
username = row[1]
langdB = row[2]
ext = row[3]
path = row[4]
hard_limit = row[6]
soft_limit = hard_limit
access = row[7]
submit_time = row[8]
print codefilename,username,langdB,ext,path,hard_limit,access,submit_time
judge()
print "-------------------"
except Exception as e:
print e
print "Error : unable to fetch data"
#cursor1.execute(sql)
#data = cursor1.fetchone()
except Exception as e:
print e
else:
# disconnect from server
db.close()
if __name__ == "__main__": #__name__ is the module name
obtain_lock()
platform_check()
system_check()
print_header()
connect_mysql()
print "end"
os.system("rm lock.txt")
"""
if(result == "Success"):
compare("out.txt","correct.txt")
"""
"""
if(result == "Compilation Error"):
data = file_read("compileError.txt")
print data
"""