strange failure in cygwin due to some of the apps being built with a WinMain,
leading them to seemingly exit immediately, which messed with the status
being returned pretty badly. perhaps cygwin was also killing the process
prematurely because it had no console? in any case, adding a pipe to cat
has forced cygwin to track the process across its entire lifetime and now
we are correctly trapping the results of all the test aps. whew. this was
a really ugly mess and popped up in some really strangely unrelated ways.
+ // make sure the guard is initialized before the threads run.
+ guard().lock();
+ guard().unlock();
+
{
// we check how long a lock and unlock of a non-locked mutex will take.
// this is important to know so that we aren't spending much of our time
{
// we check how long a lock and unlock of a non-locked mutex will take.
// this is important to know so that we aren't spending much of our time
ASSERT_TRUE(time_per_lock < 1.0, "mutex lock timing should be super fast");
}
ASSERT_TRUE(time_per_lock < 1.0, "mutex lock timing should be super fast");
}
- // make sure the guard is initialized before the threads run.
- guard().lock();
- guard().unlock();
-
amorph<ethread> thread_list;
for (int i = 0; i < DEFAULT_FISH; i++) {
amorph<ethread> thread_list;
for (int i = 0; i < DEFAULT_FISH; i++) {
ethread *q = thread_list[thread_list.elements() - 1];
ASSERT_EQUAL(q, t, "amorph pointer equivalence is required");
// start the thread we added.
ethread *q = thread_list[thread_list.elements() - 1];
ASSERT_EQUAL(q, t, "amorph pointer equivalence is required");
// start the thread we added.
- thread_list[thread_list.elements() - 1]->start(NIL);
}
time_stamp when_to_leave(DEFAULT_RUN_TIME);
}
time_stamp when_to_leave(DEFAULT_RUN_TIME);
FUNCDEF("inner_select");
// setup the file descriptor sets for the select. we check readability,
// writability and exception status.
FUNCDEF("inner_select");
// setup the file descriptor sets for the select. we check readability,
// writability and exception status.
FD_ZERO(&read_list); FD_SET(socket, &read_list);
FD_ZERO(&read_list); FD_SET(socket, &read_list);
FD_ZERO(&write_list); FD_SET(socket, &write_list);
FD_ZERO(&write_list); FD_SET(socket, &write_list);
FD_ZERO(&exceptions); FD_SET(socket, &exceptions);
FD_ZERO(&exceptions); FD_SET(socket, &exceptions);
-LOG("select D");
-timeval *farkle = new timeval;
-LOG("select D.1");
-time_stamp *t = new time_stamp();
-LOG("select D.2");
timeval time_out;
time_stamp::fill_timeval_ms(time_out, timeout);
// timeval has tv_sec=seconds, tv_usec=microseconds.
timeval time_out;
time_stamp::fill_timeval_ms(time_out, timeout);
// timeval has tv_sec=seconds, tv_usec=microseconds.
// select will tell us about the socket.
int ret = ::select(socket + 1,
(mode & SELECTING_JUST_WRITE)? NIL : &read_list,
(mode & SELECTING_JUST_READ)? NIL : &write_list,
&exceptions, &time_out);
// select will tell us about the socket.
int ret = ::select(socket + 1,
(mode & SELECTING_JUST_WRITE)? NIL : &read_list,
(mode & SELECTING_JUST_READ)? NIL : &write_list,
&exceptions, &time_out);
int error = critical_events::system_error();
int error = critical_events::system_error();
if (!ret) return 0; // nothing to report.
if (ret == SOCKET_ERROR) {
if (!ret) return 0; // nothing to report.
if (ret == SOCKET_ERROR) {
switch (error) {
// all real errors fall out to the error handling stuff.
case SOCK_EFAULT: // intentional fall-through.
switch (error) {
// all real errors fall out to the error handling stuff.
case SOCK_EFAULT: // intentional fall-through.
#endif
return 0; // not really an error.
}
#endif
return 0; // not really an error.
}
#ifdef DEBUG_RAW_SOCKET
LOG(a_sprintf("socket %u had error %d in select: %s.",
socket, error, _stack->tcpip_error_name(error).s()));
#ifdef DEBUG_RAW_SOCKET
LOG(a_sprintf("socket %u had error %d in select: %s.",
socket, error, _stack->tcpip_error_name(error).s()));
// if we got to here, then there are some things to report...
return SI_BASELINE;
}
// if we got to here, then there are some things to report...
return SI_BASELINE;
}
// uncomment for noisy version.
#undef LOG
// uncomment for noisy version.
#undef LOG
astring spocket::text_form()
{
FUNCDEF("text_form");
astring spocket::text_form()
{
FUNCDEF("text_form");
-LOG("INTO TEXT_FORM A");
astring to_return = is_client()? "client" :
(is_root_server()? "root-server" : "server");
astring to_return = is_client()? "client" :
(is_root_server()? "root-server" : "server");
-LOG("INTO TEXT_FORM B");
to_return += " spocket: ";
to_return += " spocket: ";
-LOG("INTO TEXT_FORM C");
-LOG("INTO TEXT_FORM C.1");
to_return += "connected, ";
} else {
to_return += "connected, ";
} else {
-LOG("INTO TEXT_FORM C.2");
if (was_connected()) to_return += "unconnected (was once), ";
else to_return += "never-connected, ";
if (was_connected()) to_return += "unconnected (was once), ";
else to_return += "never-connected, ";
-LOG("INTO TEXT_FORM C.3");
-LOG("INTO TEXT_FORM D");
to_return += a_sprintf("socket=%u, ", _socket);
to_return += a_sprintf("socket=%u, ", _socket);
-LOG("INTO TEXT_FORM E");
-LOG("INTO TEXT_FORM F");
to_return += a_sprintf("root-socket=%u, ", _server_socket);
to_return += a_sprintf("root-socket=%u, ", _server_socket);
-LOG("INTO TEXT_FORM G");
-LOG("INTO TEXT_FORM H");
to_return += _where->text_form().s();
to_return += _where->text_form().s();
-LOG("INTO TEXT_FORM X");
if (!_socket) return false;
if (!_socket) return false;
-LOG("conn check, _sock not null");
-
// do examination on spocket.
int sel_mode = 0;
GRAB_LOCK;
// do examination on spocket.
int sel_mode = 0;
GRAB_LOCK;
-LOG(a_sprintf("lock was grabbed, socks is %x", _socks));
try {
int ret = _socks->select(_socket, sel_mode);
try {
int ret = _socks->select(_socket, sel_mode);
-
-LOG("after select");
-
if (ret == 0) {
return true; // we are happy.
}
if (ret == 0) {
return true; // we are happy.
}
}
return true;
} catch (...) {
}
return true;
} catch (...) {
-LOG("caught exception thrown from select, returning false.");
+ LOG("caught exception thrown from select, returning false.");
LOG("Failed to open the client's connecting spocket.");
return ACCESS_DENIED;
}
LOG("Failed to open the client's connecting spocket.");
return ACCESS_DENIED;
}
-LOG(a_sprintf("hola, socket value received is: %d", _socket));
// mark the spocket for _blocking_ I/O. we want connect to sit there
// until it's connected or returns with an error.
_socks->set_non_blocking(_socket, false);
// mark the spocket for _blocking_ I/O. we want connect to sit there
// until it's connected or returns with an error.
_socks->set_non_blocking(_socket, false);
-LOG(a_sprintf("set nonblock false on : %d", _socket));
-
if (_type == BROADCAST) {
if (!_socks->set_broadcast(_socket)) return ACCESS_DENIED;
// mark the socket for broadcast capability.
if (_type == BROADCAST) {
if (!_socks->set_broadcast(_socket)) return ACCESS_DENIED;
// mark the socket for broadcast capability.
if (!_socks->set_reuse_address(_socket)) return ACCESS_DENIED;
// mark the socket so we don't get bind errors on in-use conditions.
if (!_socks->set_reuse_address(_socket)) return ACCESS_DENIED;
// mark the socket so we don't get bind errors on in-use conditions.
-LOG(a_sprintf("set reuse addr : %d", _socket));
}
if (_type == CONNECTED) {
}
if (_type == CONNECTED) {
-LOG(a_sprintf("accepted socket number is %d", accepted));
-
// mark the new spocket for non-blocking I/O.
_socks->set_non_blocking(accepted, true);
// mark the new spocket for non-blocking I/O.
_socks->set_non_blocking(accepted, true);
-LOG("after set nonblockheading");
-
//move to socks object!
int sock_hop = 1;
if (setsockopt(accepted, SOL_SOCKET, SO_KEEPALIVE, (char *)&sock_hop,
//move to socks object!
int sock_hop = 1;
if (setsockopt(accepted, SOL_SOCKET, SO_KEEPALIVE, (char *)&sock_hop,
// create the spocket address that we will connect to.
sock = new spocket(*_where);
// create the spocket address that we will connect to.
sock = new spocket(*_where);
-LOG("preview new spock A:"); LOG(sock->text_form());
*sock->_remote = _stack->convert(new_sock);
*sock->_remote = _stack->convert(new_sock);
-LOG("preview new spock B:"); LOG(sock->text_form());
sock->_socket = accepted;
sock->_socket = accepted;
-LOG("preview new spock C:"); LOG(sock->text_form());
sock->_server_socket = 0; // reset to avoid whacking.
sock->_server_socket = 0; // reset to avoid whacking.
-LOG("preview new spock D:"); LOG(sock->text_form());
sock->_was_connected = true;
sock->_was_connected = true;
-LOG("about to return this spocket as new spock:");
-LOG(sock->text_form());
outcome spocket::receive(abyte *buffer, int &size)
{
FUNCDEF("receive");
outcome spocket::receive(abyte *buffer, int &size)
{
FUNCDEF("receive");
if (_type != CONNECTED) return BAD_INPUT;
ENSURE_HEALTH(NO_CONNECTION);
if (_type != CONNECTED) return BAD_INPUT;
ENSURE_HEALTH(NO_CONNECTION);
int expected = size;
size = 0;
if (expected <= 0) return BAD_INPUT;
int expected = size;
size = 0;
if (expected <= 0) return BAD_INPUT;
int len = recv(_socket, (char *)buffer, expected, 0);
int len = recv(_socket, (char *)buffer, expected, 0);
// check to make sure we're not disconnected.
int ret = _socks->select(_socket, raw_socket::SELECTING_JUST_READ);
// check to make sure we're not disconnected.
int ret = _socks->select(_socket, raw_socket::SELECTING_JUST_READ);
if (ret & SI_DISCONNECTED) {
RECOGNIZE_DISCO;
return NO_CONNECTION;
}
if (ret & SI_DISCONNECTED) {
RECOGNIZE_DISCO;
return NO_CONNECTION;
}
// seems like more normal absence of data.
return NONE_READY;
} else if (len < 0) {
// seems like more normal absence of data.
return NONE_READY;
} else if (len < 0) {
if (critical_events::system_error() == SOCK_EWOULDBLOCK) return NONE_READY;
#ifdef DEBUG_SPOCKET
LOG(astring("The receive failed with an error ")
+ critical_events::system_error_text(critical_events::system_error()));
#endif
if (critical_events::system_error() == SOCK_EWOULDBLOCK) return NONE_READY;
#ifdef DEBUG_SPOCKET
LOG(astring("The receive failed with an error ")
+ critical_events::system_error_text(critical_events::system_error()));
#endif
if (!connected()) return NO_CONNECTION;
if (!connected()) return NO_CONNECTION;
size = len;
return OKAY;
}
size = len;
return OKAY;
}
static abyte receive_buffer[MAXIMUM_WINSOCK_MTU + 1];
// used for dumping received data into.
static abyte receive_buffer[MAXIMUM_WINSOCK_MTU + 1];
// used for dumping received data into.
-#define DEBUG_SPOCKET_TESTER
+//#define DEBUG_SPOCKET_TESTER
// uncomment for noisy version.
broadcast_spocket_tester::broadcast_spocket_tester
// uncomment for noisy version.
broadcast_spocket_tester::broadcast_spocket_tester
* Please send any updates to: fred@gruntose.com *
\*****************************************************************************/
* Please send any updates to: fred@gruntose.com *
\*****************************************************************************/
-////#include <basis/definitions.h>
#include <sockets/internet_address.h>
#include <sockets/spocket.h>
#include <sockets/tcpip_stack.h>
#include <sockets/internet_address.h>
#include <sockets/spocket.h>
#include <sockets/tcpip_stack.h>
const int PAUSE_TIME = 200;
// the snooze interval when we encounter socket underflow or overflow.
const int PAUSE_TIME = 200;
// the snooze interval when we encounter socket underflow or overflow.
-#define DEBUG_SPOCKET_TESTER
+//#define DEBUG_SPOCKET_TESTER
// uncomment for noisy version.
spocket_tester::spocket_tester(const internet_address &where)
// uncomment for noisy version.
spocket_tester::spocket_tester(const internet_address &where)
bool spocket_tester::connect()
{
if (!_socket) {
bool spocket_tester::connect()
{
if (!_socket) {
-LOG("creating new client socket");
_socket = new spocket(*_where);
}
_socket = new spocket(*_where);
}
-LOG(astring("connect socket info: ") + _socket->text_form());
outcome ret = spocket::NO_CONNECTION;
while (true) {
ret = _socket->connect();
outcome ret = spocket::NO_CONNECTION;
while (true) {
ret = _socket->connect();
bool spocket_tester::accept(bool wait)
{
if (!_root_server) {
bool spocket_tester::accept(bool wait)
{
if (!_root_server) {
-LOG("hey creating new root server socket");
_root_server = new spocket(*_where);
_root_server = new spocket(*_where);
-LOG("got past creating the root server socket");
-LOG(astring("accept root server socket info: ") + _root_server->text_form());
}
if (_socket) {
LOG("already have a socket for accept!");
return true;
}
outcome ret = spocket::NO_CONNECTION;
}
if (_socket) {
LOG("already have a socket for accept!");
return true;
}
outcome ret = spocket::NO_CONNECTION;
-LOG("int accepting loop on root server");
while (true) {
ret = _root_server->accept(_socket, false);
if (ret == spocket::OKAY) break;
while (true) {
ret = _root_server->accept(_socket, false);
if (ret == spocket::OKAY) break;
time_control::sleep_ms(100); // snooze to avoid slamming with accepts.
}
time_control::sleep_ms(100); // snooze to avoid slamming with accepts.
}
-if (_socket != NIL) {
-LOG(astring("accepted! socket info: ") + _socket->text_form());
-}
return ret == spocket::OKAY;
}
return ret == spocket::OKAY;
}
#endif
time_stamp when_to_leave(MAXIMUM_TRANSFER_WAIT);
#endif
time_stamp when_to_leave(MAXIMUM_TRANSFER_WAIT);
int full_length = 0;
while ( (full_length < size_expected) && (time_stamp() < when_to_leave) ) {
int full_length = 0;
while ( (full_length < size_expected) && (time_stamp() < when_to_leave) ) {
time_stamp start_of_receive;
int len = MAXIMUM_WINSOCK_MTU;
time_stamp start_of_receive;
int len = MAXIMUM_WINSOCK_MTU;
-LOG("FARP 3");
-if (!_socket) {
- LOG("WHAT? SOCKET IS NULL!!!");
-}
-////time_control::sleep_ms(PAUSE_TIME);
-LOG("FARP 3.1");
-LOG(astring("socket info: ") + _socket->text_form());
-LOG("FARP 3.2");
outcome ret = _socket->receive(receive_buffer, len);
outcome ret = _socket->receive(receive_buffer, len);
if (ret != spocket::OKAY) {
if (ret == spocket::NONE_READY) {
if (len != 0) LOG(a_sprintf("supposedly nothing was received (%d bytes)", len));
if (ret != spocket::OKAY) {
if (ret == spocket::NONE_READY) {
if (len != 0) LOG(a_sprintf("supposedly nothing was received (%d bytes)", len));
-/// time_control::sleep_ms(PAUSE_TIME);
_socket->await_readable(PAUSE_TIME);
continue;
} else break;
_socket->await_readable(PAUSE_TIME);
continue;
} else break;
bool spocket_tester::perform_test(int size, int count,
testing_statistics &stats)
{
bool spocket_tester::perform_test(int size, int count,
testing_statistics &stats)
{
-#ifdef DEBUG_SPOCKET_TESTER
- LOG("into perf test");
-#endif
-
// the statics are used to generate our random buffer for sending.
static abyte garbage_buffer[MAXIMUM_WINSOCK_MTU + 1];
static bool garbage_initialized = false;
// the statics are used to generate our random buffer for sending.
static abyte garbage_buffer[MAXIMUM_WINSOCK_MTU + 1];
static bool garbage_initialized = false;
// if our static buffer full of random stuff was never initialized, we do
// so now. this supports efficiently re-using the tester if desired.
if (!garbage_initialized) {
// if our static buffer full of random stuff was never initialized, we do
// so now. this supports efficiently re-using the tester if desired.
if (!garbage_initialized) {
- LOG("initializing random send buffer.");
// note the less than or equal; we know we have one more byte to fill.
for (int i = 0; i <= MAXIMUM_WINSOCK_MTU; i++)
garbage_buffer[i] = randomizer.inclusive(0, 255);
garbage_initialized = true;
// note the less than or equal; we know we have one more byte to fill.
for (int i = 0; i <= MAXIMUM_WINSOCK_MTU; i++)
garbage_buffer[i] = randomizer.inclusive(0, 255);
garbage_initialized = true;
- LOG("random send buffer initialized.");
}
// reset the statistical package.
}
// reset the statistical package.
int test_spocket::execute()
{
FUNCDEF("execute");
int test_spocket::execute()
{
FUNCDEF("execute");
ip_address_holder ip_address; // accumulates the source address.
int rcv_port = 0;
bool is_client = false;
ip_address_holder ip_address; // accumulates the source address.
int rcv_port = 0;
bool is_client = false;
const int DEFAULT_SEND_SIZE = 1008;
const int DEFAULT_SEND_COUNT = 10;
const int DEFAULT_SEND_SIZE = 1008;
const int DEFAULT_SEND_COUNT = 10;
if (_global_argc < 6) {
if (_global_argc > 1) {
LOG("\
if (_global_argc < 6) {
if (_global_argc > 1) {
LOG("\
// only parse the parameters if we got enough from the user; otherwise we accept our
// defaults to do a simple test run.
if (_global_argc >= 6) {
// only parse the parameters if we got enough from the user; otherwise we accept our
// defaults to do a simple test run.
if (_global_argc >= 6) {
if (!parse_address(_global_argv[1], ip_address)) {
LOG("failed to parse source address.");
return 9283;
}
if (!parse_address(_global_argv[1], ip_address)) {
LOG("failed to parse source address.");
return 9283;
}
LOG(a_sprintf("\tParsed a source of: \"%d.%d.%d.%d\".",
(int)ip_address[0], (int)ip_address[1], (int)ip_address[2],
(int)ip_address[3]));
LOG(a_sprintf("\tParsed a source of: \"%d.%d.%d.%d\".",
(int)ip_address[0], (int)ip_address[1], (int)ip_address[2],
(int)ip_address[3]));
LOG(a_sprintf("\tGot a send count of %d.", send_count));
}
LOG(a_sprintf("\tGot a send count of %d.", send_count));
}
// package our parameters in a form the tester likes.
internet_address to_pass(byte_array(4, ip_address), "", rcv_port);
// package our parameters in a form the tester likes.
internet_address to_pass(byte_array(4, ip_address), "", rcv_port);
// choose the appropriate action based on our role.
bool outcome;
if (is_client) {
// choose the appropriate action based on our role.
bool outcome;
if (is_client) {
-LOG("client side is connecting");
outcome = tester->connect();
} else {
outcome = tester->connect();
} else {
-LOG("server side is accepting");
outcome = tester->accept(_global_argc != 1);
}
if (!outcome) {
outcome = tester->accept(_global_argc != 1);
}
if (!outcome) {
LOG(astring("Failed to ") + action + " on the tester.");
return 10;
}
LOG(astring("Failed to ") + action + " on the tester.");
return 10;
}
-LOG("success after conn/accept");
-
-LOG("OY POINT T");
if (_global_argc == 1) {
// launch a paired duplicate of our test so we can chat.
if (_global_argc == 1) {
// launch a paired duplicate of our test so we can chat.
+ a_sprintf("%d", DEFAULT_SEND_SIZE) + " " + a_sprintf("%d", DEFAULT_SEND_COUNT),
launch_process::RETURN_IMMEDIATELY, kidnum);
ASSERT_EQUAL(result, 0, "launching paired process should start successfully");
+ a_sprintf("%d", DEFAULT_SEND_SIZE) + " " + a_sprintf("%d", DEFAULT_SEND_COUNT),
launch_process::RETURN_IMMEDIATELY, kidnum);
ASSERT_EQUAL(result, 0, "launching paired process should start successfully");
// now we try again accepting from our client side.
outcome = tester->accept();
//hmmm: redundant below.
// now we try again accepting from our client side.
outcome = tester->accept();
//hmmm: redundant below.
if (!outcome) {
const char *action = is_client? "connect" : "accept";
if (!outcome) {
const char *action = is_client? "connect" : "accept";
LOG(astring("Failed to ") + action + " on the tester.");
return 10;
}
}
LOG(astring("Failed to ") + action + " on the tester.");
return 10;
}
}
// so, we're connected. try sending the test packages out.
testing_statistics stats; // to be filled by the tester.
// so, we're connected. try sending the test packages out.
testing_statistics stats; // to be filled by the tester.
outcome = tester->perform_test(send_size, send_count * 2, stats);
// multiply send_count since we count each side as one.
outcome = tester->perform_test(send_size, send_count * 2, stats);
// multiply send_count since we count each side as one.
if (!outcome) {
LOG("Failed out of send_data; maybe other side terminated.");
}
if (!outcome) {
LOG("Failed out of send_data; maybe other side terminated.");
}
stats.total_runs /= 2; // cut down to the real number of tests.
stats.total_runs /= 2; // cut down to the real number of tests.
if (!stats.total_runs)
stats.total_runs = 1;
if (!stats.total_runs)
stats.total_runs = 1;
// now report on the stats that we get from the data sending.
LOG(a_sprintf("Report for %d completed test cycles.", stats.total_runs));
LOG("");
// now report on the stats that we get from the data sending.
LOG(a_sprintf("Report for %d completed test cycles.", stats.total_runs));
LOG("");
# now, vary the flag configuration based on the flags that have been set.
# now, vary the flag configuration based on the flags that have been set.
+####override for windows since things are broken with WinMain
+###export CONSOLE_MODE = true
+
ifneq "$(CONSOLE_MODE)" ""
# console type of applications are built using the static flag so that
# they are more redistributable.
ifneq "$(CONSOLE_MODE)" ""
# console type of applications are built using the static flag so that
# they are more redistributable.
total_exitval=0;
for program_name in ${RUN_TARGETS}; do
base=$(basename $program_name);
total_exitval=0;
for program_name in ${RUN_TARGETS}; do
base=$(basename $program_name);
- "$program_name";
- exitval=$?;
+ if [ "$OP_SYSTEM" == "WIN32" ]; then
+ # extra step to force win32 apps to stay held in our grip,
+ # since they will float off and appear to have stopped when
+ # run by cygwin. but by grabbing the i/o stream, we know it's
+ # running until it's done.
+ "$program_name" 2>&1 | cat
+ # we care about the exit status of the first process in the pipe,
+ # which is the app being run.
+ exitval=${PIPESTATUS[0]}
+ else
+ "$program_name"
+ exitval=$?;
+ fi
if [ $exitval -ne 0 ]; then
echo "ERROR: $program_name exits with $exitval at $(date)";
total_exitval=$(($total_exitval + 1));
if [ $exitval -ne 0 ]; then
echo "ERROR: $program_name exits with $exitval at $(date)";
total_exitval=$(($total_exitval + 1));