📄 labview_test_controller.cpp
字号:
}
}
else
{
this->reply ("Unrecognized command\n");
return -1;
}
return 0;
}
int
Peer::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 ();
}
int
Test::run (void)
{
this->running_ = true;
try
{
this->status_ = (this->entry_) (this->argc_, this->argv_);
}
catch (...)
{
// Try to note this exception then save the log file before bailing out.
DWORD bl;
char msg[256];
sprintf (msg, "Exception in %s caught by labview_test_controller\n",
this->name_);
WriteFile (logf, msg, (DWORD)strlen(msg), &bl, 0);
FlushFileBuffers (logf);
CloseHandle (logf);
throw;
}
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;
}
bool
Test::status (int *exit_status)
{
if (this->running_)
return false; // still running
*exit_status = this->status_;
this->cleanup ();
return true;
}
int
Test::wait (void)
{
WaitForSingleObject (this->thr_handle_, INFINITE);
if (!this->running_)
this->cleanup ();
return this->status_;
}
void
Test::kill (void)
{
TerminateThread (this->thr_handle_, -1);
this->cleanup ();
this->running_ = false;
this->status_ = -1;
}
// Clean up remnants of a test run.
void
Test::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 __stdcall
test_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 __stdcall
peer_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 __stdcall
run_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 + -