{
FUNCDEF("execute");
+ // 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
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++) {
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);
+ q->start(NIL);
}
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.
-LOG("select A");
FD_ZERO(&read_list); FD_SET(socket, &read_list);
-LOG("select B");
FD_ZERO(&write_list); FD_SET(socket, &write_list);
-LOG("select C");
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.
-LOG("select E");
// 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);
-LOG("select F");
int error = critical_events::system_error();
-LOG("select G");
-
if (!ret) return 0; // nothing to report.
if (ret == SOCKET_ERROR) {
-LOG("select H");
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.
}
-LOG("select I");
#ifdef DEBUG_RAW_SOCKET
LOG(a_sprintf("socket %u had error %d in select: %s.",
socket, error, _stack->tcpip_error_name(error).s()));
return SI_ERRONEOUS;
}
-LOG("select J");
// if we got to here, then there are some things to report...
return SI_BASELINE;
}
namespace sockets {
-#define DEBUG_SPOCKET
+//#define DEBUG_SPOCKET
// uncomment for noisy version.
#undef LOG
astring spocket::text_form()
{
FUNCDEF("text_form");
-LOG("INTO TEXT_FORM A");
astring to_return = is_client()? "client" :
(is_root_server()? "root-server" : "server");
-LOG("INTO TEXT_FORM B");
to_return += " spocket: ";
-LOG("INTO TEXT_FORM C");
if (connected()) {
-LOG("INTO TEXT_FORM C.1");
to_return += "connected, ";
} else {
-LOG("INTO TEXT_FORM C.2");
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);
-LOG("INTO TEXT_FORM E");
if (is_root_server()) {
-LOG("INTO TEXT_FORM F");
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();
-LOG("INTO TEXT_FORM X");
return to_return;
}
if (!_socket) return false;
-LOG("conn check, _sock not null");
-
// 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);
-
-LOG("after select");
-
if (ret == 0) {
return true; // we are happy.
}
}
return true;
} catch (...) {
-LOG("caught exception thrown from select, returning false.");
+ LOG("caught exception thrown from select, returning false.");
return false;
}
}
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);
-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 (!_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) {
return ACCESS_DENIED;
}
-LOG(a_sprintf("accepted socket number is %d", accepted));
-
// 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,
// 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);
-LOG("preview new spock B:"); LOG(sock->text_form());
sock->_socket = accepted;
-LOG("preview new spock C:"); LOG(sock->text_form());
sock->_server_socket = 0; // reset to avoid whacking.
-LOG("preview new spock D:"); LOG(sock->text_form());
sock->_was_connected = true;
-LOG("about to return this spocket as new spock:");
-LOG(sock->text_form());
return OKAY;
}
outcome spocket::receive(abyte *buffer, int &size)
{
FUNCDEF("receive");
-LOG("RECV A");
CHECK_BOGUS(NONE_READY);
-LOG("RECV B");
if (_type != CONNECTED) return BAD_INPUT;
ENSURE_HEALTH(NO_CONNECTION);
-LOG("RECV C");
int expected = size;
size = 0;
if (expected <= 0) return BAD_INPUT;
-LOG("RECV D");
GRAB_LOCK;
-LOG("RECV E");
int len = recv(_socket, (char *)buffer, expected, 0);
-LOG("RECV F");
if (!len) {
-LOG("RECV F.1");
// check to make sure we're not disconnected.
int ret = _socks->select(_socket, raw_socket::SELECTING_JUST_READ);
-LOG("RECV F.2");
if (ret & SI_DISCONNECTED) {
RECOGNIZE_DISCO;
return NO_CONNECTION;
}
-LOG("RECV F.3");
// seems like more normal absence of data.
return NONE_READY;
} else if (len < 0) {
-LOG("RECV F.4");
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
-LOG("RECV F.5");
if (!connected()) return NO_CONNECTION;
-LOG("RECV F.6");
return ACCESS_DENIED;
}
-LOG("RECV G");
size = len;
return OKAY;
}
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
* 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>
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)
bool spocket_tester::connect()
{
if (!_socket) {
-LOG("creating new client socket");
_socket = new spocket(*_where);
}
-LOG(astring("connect socket info: ") + _socket->text_form());
outcome ret = spocket::NO_CONNECTION;
while (true) {
ret = _socket->connect();
bool spocket_tester::accept(bool wait)
{
if (!_root_server) {
-LOG("hey creating new root server socket");
_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;
-LOG("int accepting loop on root server");
while (true) {
ret = _root_server->accept(_socket, false);
if (ret == spocket::OKAY) break;
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;
}
#endif
time_stamp when_to_leave(MAXIMUM_TRANSFER_WAIT);
-LOG("FARP 1");
int full_length = 0;
while ( (full_length < size_expected) && (time_stamp() < when_to_leave) ) {
-LOG("FARP 2");
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);
-LOG("FARP 4");
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;
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;
// 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;
- LOG("random send buffer initialized.");
}
// reset the statistical package.
int test_spocket::execute()
{
FUNCDEF("execute");
-LOG("OY POINT A");
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;
-LOG("OY POINT B");
-
if (_global_argc < 6) {
if (_global_argc > 1) {
LOG("\
}
}
-LOG("OY POINT C");
-
// 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) {
-LOG("OY POINT D");
if (!parse_address(_global_argv[1], ip_address)) {
LOG("failed to parse source address.");
return 9283;
}
-LOG("OY POINT E");
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("OY POINT Q");
-
// 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) {
-LOG("client side is connecting");
outcome = tester->connect();
} else {
-LOG("server side is accepting");
outcome = tester->accept(_global_argc != 1);
}
if (!outcome) {
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.
+ 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");
-LOG("OY POINT U.1");
// now we try again accepting from our client side.
outcome = tester->accept();
//hmmm: redundant below.
-LOG("OY POINT U.2");
if (!outcome) {
const char *action = is_client? "connect" : "accept";
-LOG("OY POINT U.3");
LOG(astring("Failed to ") + action + " on the tester.");
return 10;
}
}
-LOG("OY POINT V");
// so, we're connected. try sending the test packages out.
testing_statistics stats; // to be filled by the tester.
-LOG("OY POINT V.1");
outcome = tester->perform_test(send_size, send_count * 2, stats);
// multiply send_count since we count each side as one.
-LOG("OY POINT V.2");
if (!outcome) {
LOG("Failed out of send_data; maybe other side terminated.");
}
-LOG("OY POINT V.3");
stats.total_runs /= 2; // cut down to the real number of tests.
-LOG("OY POINT V.4");
if (!stats.total_runs)
stats.total_runs = 1;
-LOG("OY POINT W");
-
// 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.
+####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.
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));