88 */
99
1010#include " judgingthread.h"
11+ #include " LemonType.hpp"
1112#include " base/LemonLog.hpp"
1213#include " base/settings.h"
1314#include " core/judgesharedvariables.h"
@@ -86,8 +87,14 @@ void JudgingThread::setFullScore(int score) { fullScore = score; }
8687
8788void JudgingThread::setTimeLimit (int limit) { timeLimit = limit; }
8889
90+ void JudgingThread::setRawTimeLimit (int limit) { rawTimeLimit = limit; }
91+
8992void JudgingThread::setMemoryLimit (int limit) { memoryLimit = limit; }
9093
94+ void JudgingThread::setRawMemoryLimit (int limit) { rawMemoryLimit = limit; }
95+
96+ void JudgingThread::setInterpreterAsWatcher (bool use) { interpreterAsWatcher = use; }
97+
9198auto JudgingThread::getTimeUsed () const -> int { return timeUsed; }
9299
93100auto JudgingThread::getMemoryUsed () const -> int { return memoryUsed; }
@@ -888,7 +895,13 @@ void JudgingThread::runProgram() {
888895#ifdef Q_OS_LINUX
889896 // TODO: rewrite with cgroup
890897 QFile watcher (workingDirectory + QUuid::createUuid ().toString (QUuid::Id128));
891- QFile::copy (" :/watcher/watcher_unix" , watcher.fileName ());
898+
899+ if (interpreterAsWatcher) {
900+ QFile::copy (executableFile, watcher.fileName ());
901+ } else {
902+ QFile::copy (" :/watcher/watcher_unix" , watcher.fileName ());
903+ }
904+
892905 watcher.setPermissions (QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner);
893906 auto *runner = new QProcess (this );
894907 QStringList argumentsList;
@@ -925,7 +938,8 @@ void JudgingThread::runProgram() {
925938
926939 argumentsList << watcher.fileName ();
927940
928- argumentsList << QString (" \" %1\" %2" ).arg (executableFile, arguments);
941+ argumentsList << executableFile;
942+ argumentsList << arguments;
929943
930944 if (task->getStandardInputCheck ()) {
931945 argumentsList << QFileInfo (inputFile).absoluteFilePath ();
@@ -942,6 +956,20 @@ void JudgingThread::runProgram() {
942956 argumentsList << " _tmperr" ;
943957 argumentsList << QString (" %1" ).arg (timeLimit + extraTime);
944958 argumentsList << QString (" %1" ).arg (memoryLimit);
959+ argumentsList << QString (" %1" ).arg (rawTimeLimit);
960+ argumentsList << QString (" %1" ).arg (rawMemoryLimit);
961+
962+ if (task->getStandardInputCheck ()) {
963+ argumentsList << " " ;
964+ } else {
965+ argumentsList << task->getInputFileName ();
966+ }
967+
968+ if (task->getStandardOutputCheck ()) {
969+ argumentsList << " " ;
970+ } else {
971+ argumentsList << task->getOutputFileName ();
972+ }
945973
946974 qDebug () << argumentsList;
947975
@@ -952,11 +980,19 @@ void JudgingThread::runProgram() {
952980#else
953981
954982 QFile watcher (workingDirectory + QUuid::createUuid ().toString (QUuid::Id128));
955- QFile::copy (" :/watcher/watcher_unix" , watcher.fileName ());
983+
984+ if (interpreterAsWatcher) {
985+ QFile::copy (executableFile, watcher.fileName ());
986+ } else {
987+ QFile::copy (" :/watcher/watcher_unix" , watcher.fileName ());
988+ }
989+
956990 watcher.setPermissions (QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner);
957991 auto *runner = new QProcess (this );
958992 QStringList argumentsList;
959- argumentsList << QString (" \" %1\" %2" ).arg (executableFile, arguments);
993+
994+ argumentsList << executableFile;
995+ argumentsList << arguments;
960996
961997 if (task->getStandardInputCheck ()) {
962998 argumentsList << QFileInfo (inputFile).absoluteFilePath ();
@@ -973,6 +1009,22 @@ void JudgingThread::runProgram() {
9731009 argumentsList << " _tmperr" ;
9741010 argumentsList << QString (" %1" ).arg (timeLimit + extraTime);
9751011 argumentsList << QString (" %1" ).arg (memoryLimit);
1012+ argumentsList << QString (" %1" ).arg (rawTimeLimit);
1013+ argumentsList << QString (" %1" ).arg (rawMemoryLimit);
1014+
1015+ if (task->getStandardInputCheck ()) {
1016+ argumentsList << " " ;
1017+ } else {
1018+ argumentsList << task->getInputFileName ();
1019+ }
1020+
1021+ if (task->getStandardOutputCheck ()) {
1022+ argumentsList << " " ;
1023+ } else {
1024+ argumentsList << task->getOutputFileName ();
1025+ }
1026+
1027+ qDebug () << argumentsList;
9761028
9771029 runner->setProcessEnvironment (environment);
9781030 runner->setWorkingDirectory (workingDirectory);
@@ -984,6 +1036,7 @@ void JudgingThread::runProgram() {
9841036 delete runner;
9851037 score = 0 ;
9861038 result = CannotStartProgram;
1039+ message = " Start runner failed" ;
9871040 return ;
9881041 }
9891042
@@ -1021,65 +1074,61 @@ void JudgingThread::runProgram() {
10211074 runner->waitForFinished (-1 );
10221075 delete runner;
10231076 score = 0 ;
1024- result = TimeLimitExceeded;
10251077 timeUsed = memoryUsed = -1 ;
1026- return ;
1027- }
1028-
1029- int code = runner->exitCode ();
1030-
1031- if (code == 1 ) {
1032- delete runner;
1033- score = 0 ;
1078+ // Watcher usually needs to handle the situation of program timeout and kill it. Therefore, it is
1079+ // abnormal for watcher to timeout itself, and report FAIL instead of TLE.
10341080 result = CannotStartProgram;
1035- timeUsed = memoryUsed = - 1 ;
1081+ message = " Watcher time limit exceeded " ;
10361082 return ;
10371083 }
10381084
1039- if (code == 2 ) {
1040- delete runner;
1041- score = 0 ;
1042- result = RunTimeError;
1043- QFile file (workingDirectory + " _tmperr" );
1044-
1045- if (file.open (QFile::ReadOnly)) {
1046- QTextStream stream (&file);
1047- message = stream.readAll ();
1048- file.close ();
1049- }
1050-
1051- timeUsed = memoryUsed = -1 ;
1052- return ;
1085+ {
1086+ QString out = QString::fromLocal8Bit (runner->readAllStandardOutput ().constData ());
1087+ QTextStream stream (&out, QIODevice::ReadOnly);
1088+ stream >> timeUsed >> memoryUsed;
10531089 }
10541090
1055- QString out = QString::fromLocal8Bit (runner->readAllStandardOutput ().constData ());
1056- QTextStream stream (&out, QIODevice::ReadOnly);
1057- stream >> timeUsed >> memoryUsed;
1091+ message = QString::fromLocal8Bit (runner->readAllStandardError ().constData ());
10581092
1059- if (memoryUsed <= 0 )
1060- memoryLimit = -1 ;
1061-
1062- if (code == 3 ) {
1063- delete runner;
1064- score = 0 ;
1065- result = TimeLimitExceeded;
1066- timeUsed = -1 ;
1067- return ;
1068- }
1093+ enum : int {
1094+ RS_AC = 0 ,
1095+ RS_FAIL = 1 ,
1096+ RS_RE = 2 ,
1097+ RS_TLE = 3 ,
1098+ RS_MLE = 4 ,
1099+ };
10691100
1070- if (code == 4 ) {
1071- delete runner;
1072- score = 0 ;
1073- result = MemoryLimitExceeded;
1074- memoryUsed = -1 ;
1075- return ;
1076- }
1101+ int code = runner->exitCode ();
10771102
1078- if (memoryUsed > memoryLimit * 1024LL * 1024 ) {
1079- delete runner;
1080- score = 0 ;
1081- result = MemoryLimitExceeded;
1082- return ;
1103+ switch (code) {
1104+ case RS_RE :
1105+ result = RunTimeError;
1106+ score = 0 ;
1107+ [[fallthrough]] ;
1108+ case RS_AC : {
1109+ QFile file (workingDirectory + " _tmperr" );
1110+ if (file.open (QFile::ReadOnly)) {
1111+ message += file.readAll ().right (1024 );
1112+ file.close ();
1113+ }
1114+ } break ;
1115+ case RS_FAIL :
1116+ result = CannotStartProgram;
1117+ score = 0 ;
1118+ break ;
1119+ case RS_TLE :
1120+ result = TimeLimitExceeded;
1121+ score = 0 ;
1122+ break ;
1123+ case RS_MLE :
1124+ result = MemoryLimitExceeded;
1125+ score = 0 ;
1126+ break ;
1127+ default :
1128+ result = CannotStartProgram;
1129+ score = 0 ;
1130+ message = QString (" Watcher reported an invalid result: %1" ).arg (code);
1131+ break ;
10831132 }
10841133
10851134 delete runner;
0 commit comments