📄 labview_test_controller.cpp
字号:
0, // security CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); SetStdHandle (STD_OUTPUT_HANDLE, logf); SetStdHandle (STD_ERROR_HANDLE, logf); } } else { this->reply ("Unrecognized command\n"); return -1; } return 0;}intPeer::reply (const char *msg){ int len = (int)strlen (msg); // size_t -> int return send (this->handle_, msg, len, 0) > 0 ? 0 : -1;}Test::~Test (){ this->cleanup ();}intTest::run (void){ this->running_ = true; this->status_ = (this->entry_) (this->argc_, this->argv_); this->running_ = false; // It's possible to cleanup() here; however, that would introduce a race // with start() following beginthreadex(). So do all the cleanup on user // action - either getting status, waiting, killing, or running another // test. Or, terminating the connection. return 0;}const char *Test::start (const char *name){ if (this->running_) return "Already running\n"; const char *msg = 0; // Reset test status to not inadvertantly report a previous test. this->status_ = -1; this->cleanup (); // Resets cmdline_, argc_, argv_ // The command line is part-way through being tokenized by strtok(). It // left off after the program name. Anything remaining are the command // line arguments for the program. Pick off whatever is there, copy it // to the cmdline_ array and fill in argc_/argv_ for the eventual run. strcpy (this->name_, name); this->argv_[0] = this->name_; this->argc_ = 1; size_t cmdchars = 0; for (char *token = strtok (0, "\t \n\r"); token != 0 && (cmdchars + strlen (token) + 1) < CMDLINE_LEN; token = strtok (0, "\t \n\r")) { // We have a new token and it will fit in cmdline_. Copy it to the // next spot in cmdline_, add it to argv_/argc_ then update cmdchars // to account for the copied-in token and its nul terminator. strcpy (&this->cmdline_[cmdchars], token); this->argv_[this->argc_] = &this->cmdline_[cmdchars]; ++this->argc_; cmdchars += (strlen (token) + 1); } char libspec[1024]; sprintf (libspec, "%s.dll", name); if ((this->dll_handle_ = LoadLibrary (libspec)) == NULL) return format_errmsg (GetLastError (), libspec); this->entry_ = (TEST_FUNC) GetProcAddress (this->dll_handle_, "main"); if (this->entry_ == NULL) { msg = format_errmsg (GetLastError (), "main"); this->cleanup (); return msg; } else { unsigned int thread_id; /* unused */ uintptr_t h = _beginthreadex (0, // security 1024 * 1024, // stack size run_test, // entrypoint (void *)this, // arglist 0, // initflag &thread_id); // thread ID this->thr_handle_ = (HANDLE) h; if (h == 0) // Test thread may have access to thr_handle_ { msg = format_errmsg (GetLastError (), "spawn"); this->cleanup (); return msg; } } return 0;}boolTest::status (int *exit_status){ if (this->running_) return false; // still running *exit_status = this->status_; this->cleanup (); return true;}intTest::wait (void){ WaitForSingleObject (this->thr_handle_, INFINITE); if (!this->running_) this->cleanup (); return this->status_;}voidTest::kill (void){ TerminateThread (this->thr_handle_, -1); this->cleanup (); this->running_ = false; this->status_ = -1;}// Clean up remnants of a test run.voidTest::cleanup (void){ if (this->dll_handle_ != NULL) { FreeLibrary (this->dll_handle_); this->dll_handle_ = NULL; } if (this->thr_handle_ != 0) { CloseHandle (this->thr_handle_); this->thr_handle_ = 0; } this->entry_ = 0; this->argc_ = 0; for (int i = 0; i < ARGV_SIZE; ++i) this->argv_[i] = 0; memset (this->cmdline_, 0, CMDLINE_LEN);}static unsigned int __stdcalltest_control (void * /* param */){ // cd to ace dir?? (can this be an env variable?) // redirect stdout/stderr to a file logf = CreateFile (LogName, FILE_ALL_ACCESS, FILE_SHARE_READ, 0, // security OPEN_ALWAYS, // Don't crush a previous one FILE_ATTRIBUTE_NORMAL, 0); if (logf == INVALID_HANDLE_VALUE) perror (LogName); else { SetFilePointer (logf, 0, 0, FILE_END); // Append new content SetStdHandle (STD_OUTPUT_HANDLE, logf); SetStdHandle (STD_ERROR_HANDLE, logf); } WORD want; WSADATA offer; want = MAKEWORD (2, 2); if (0 != WSAStartup (want, &offer)) { perror ("WSAStartup"); CloseHandle (logf); return WSAGetLastError (); } // listen on port 8888 (can I set an env variable for this?) SOCKET acceptor = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); sockaddr_in listen_addr; memset (&listen_addr, 0, sizeof (listen_addr)); listen_addr.sin_family = AF_INET; listen_addr.sin_addr.s_addr = INADDR_ANY; listen_addr.sin_port = htons (8888); if (SOCKET_ERROR == bind (acceptor, (struct sockaddr *)&listen_addr, sizeof (listen_addr))) { perror ("bind"); } else { listen (acceptor, 10); SOCKET peer; while ((peer = accept (acceptor, 0, 0)) != INVALID_SOCKET) { Peer *p = new Peer (peer); if (p == 0) { perror ("Out of memory"); closesocket (peer); peer = INVALID_SOCKET; continue; } if (0 == _beginthreadex (0, // security 64 * 1024, // stack size peer_svc, // entrypoint (void *)p, // param 0, // creation flags 0)) // ptr to thread id { perror ("beginthreadex peer"); closesocket (peer); delete p; } p = 0; peer = INVALID_SOCKET; } perror ("accept"); } closesocket (acceptor); WSACleanup (); return 0;}// Entrypoint for thread that's spawned to run a peer's session. Direct// control to the peer class.static unsigned int __stdcallpeer_svc (void *peer_p){ Peer *p = (Peer *)peer_p; DWORD status = p->svc (); delete p; return status;}// Entrypoint for the thread spawned to run a test. The thread arg is the// Test * - call back to the test's run() method; return the test exit code// as the thread's return value.static unsigned int __stdcallrun_test (void *test_p){ Test *t = (Test *)test_p; return t->run ();}// Format a Windows system or Winsock error message given an error code.static const char *format_errmsg (unsigned int errcode, const char *prefix){ static const size_t errmsgsize = 1024; static char errmsg[errmsgsize]; sprintf (errmsg, "%s: ", prefix); size_t len = strlen (errmsg); char *next = &errmsg[len]; size_t max_fmt = errmsgsize - len; if (0 != FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, errcode, 0, // Use default language next, (DWORD)max_fmt, 0)) { strcat (errmsg, "\n"); return errmsg; } errno = errcode; char *msg = _strerror (prefix); sprintf (errmsg, "err %d: %s", errcode, msg); return errmsg;}#ifdef TEST_RUNNER_EXPORTS#define TEST_RUNNER_API __declspec(dllexport)#else#define TEST_RUNNER_API __declspec(dllimport)#endif__declspec(dllexport) int test_entry(void){ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -