http://www.kirstenfan.com/galleries/magazines/fhm2002100sexy/002.jpg -- studies show charming women love computer programmers......

This commit is contained in:
mpc
2004-07-03 11:05:23 +00:00
committed by zzz
parent 4b8ac81669
commit a13693161a
11 changed files with 517 additions and 27 deletions

View File

@@ -0,0 +1,130 @@
/*
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the author nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cassert>
#include <cstdarg>
#include <cstdio>
#include <iostream>
#include <string>
using namespace std;
#include "time.hpp"
#include "logger.hpp"
using namespace Libsockthread;
/*
* Closes the log file
*/
void Logger::close(void)
{
logger_m.lock();
if (logf == 0) {
logger_m.unlock();
return;
}
if (fclose(logf) == EOF) {
cerr_m.lock();
cerr << "fclose() failed: " << strerror(errno) << '\n';
cerr_m.unlock();
}
logf = 0;
logger_m.unlock();
}
/*
* Sends a line to the log file. Uses variable arguments just like printf().
*/
void Logger::log(priority_t priority, const char* format, ...)
{
if (priority < get_loglevel())
return;
char ll;
switch (priority) {
case Logger::DEBUG:
ll = 'D';
break;
case Logger::MINOR:
ll = 'M';
break;
case Logger::INFO:
ll = 'I';
break;
case Logger::WARN:
ll = 'W';
break;
case Logger::ERROR:
ll = 'E';
break;
default:
ll = '?';
}
va_list ap;
va_start(ap, format);
string s;
Time t;
logger_m.lock();
assert(logf != 0);
fprintf(logf, "%c@%s: ", ll, t.utc(s).c_str());
vfprintf(logf, format, ap);
fputc('\n', logf);
va_end(ap);
if (fflush(logf) == EOF) {
cerr_m.lock();
cerr << "fflush() failed: " << strerror(errno) << '\n';
cerr_m.unlock();
}
logger_m.unlock();
return;
}
/*
* Opens a log file for appending. If there already is an open log file, then
* it is closed and the new one is opened.
*
* file - file location to open
*/
void Logger::open(const string& file)
{
close();
logger_m.lock();
logf = fopen(file.c_str(), "a");
logger_m.unlock();
if (logf == NULL) {
cerr_m.lock();
cerr << "fopen() failed (" << file << "): " << strerror(errno) << '\n';
cerr_m.unlock();
throw Logger_error("Error opening log file");
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the author nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LIBSOCKTHREAD_LOGGER_HPP
#define LIBSOCKTHREAD_LOGGER_HPP
namespace Libsockthread {
class Logger {
public:
typedef enum {DEBUG = 0, MINOR = 1, INFO = 2, WARN = 3, ERROR = 4}
priority_t;
Logger(void)
: logf(0), loglevel(Logger::DEBUG) { }
~Logger(void) { close(); }
void close(void);
void log(priority_t priority, const char* format, ...);
priority_t get_loglevel(void) const
{ mutex.lock(); priority_t ll = loglevel; mutex.unlock(); return ll; }
void open(const string& file); // throws Logger_error
void set_loglevel(priority_t priority)
{ mutex.lock(); loglevel = priority; mutex.unlock(); }
private:
Mutex cerr_m;
FILE* logf;
priority_t loglevel;
Mutex logger_m;
};
class Logger_error : public runtime_error {
public:
Logger_error(const string& s)
: runtime_error(s) { }
};
}
#endif // LIBSOCKTHREAD_LOGGER_HPP

View File

@@ -30,8 +30,16 @@
// Modelled after JThread by Jori Liesenborgs
#include <cassert>
#include "platform.hpp"
#ifdef WINTHREAD
#include <windows.h>
#else
#include <pthread.h>
#endif
using namespace std;
#include "mutex.hpp"
using namespace Libsockthread;
/*
* Creates a mutex
@@ -39,10 +47,10 @@
Mutex::Mutex(void)
{
#ifdef WINTHREAD
mutex = CreateMutex(NULL, FALSE, NULL);
assert(mutex != NULL);
mutex = CreateMutex(0, false, 0);
assert(mutex != 0);
#else
int rc = pthread_mutex_init(&mutex, NULL);
int rc = pthread_mutex_init(&mutex, 0);
assert(rc == 0);
#endif
}
@@ -71,7 +79,7 @@ void Mutex::lock(void)
assert(rc != WAIT_FAILED);
#else
int rc = pthread_mutex_lock(&mutex);
assert(rc == 0);
assert(rc == 0); // if it stops here, it is probably from a deadlock
#endif
}
@@ -88,3 +96,39 @@ void Mutex::unlock(void)
assert(rc == 0);
#endif
}
#ifdef UNIT_TEST
// g++ -Wall -c thread.cpp -o thread.o
// g++ -Wall -DUNIT_TEST -c mutex.cpp -o mutex.o
// g++ -Wall -DUNIT_TEST mutex.o thread.o -o mutex -lpthread
#include <iostream>
#include <ctime>
#include "thread.hpp"
Mutex widget;
int main(void)
{
class Mutex_test : public Thread
{
public:
Mutex_test(int n)
: testval(n) {}
void* thread(void)
{
widget.lock();
cout << "I got it! thread #" << testval << '\n';
widget.unlock();
return 0;
}
private:
int testval;
};
Mutex_test t1(1);
Mutex_test t2(2);
Mutex_test t3(3);
return 0;
}
#endif // UNIT_TEST

View File

@@ -30,8 +30,8 @@
// Modelled after JThread by Jori Liesenborgs
#ifndef MUTEX_HPP
#define MUTEX_HPP
#ifndef LIBSOCKTHREAD_MUTEX_HPP
#define LIBSOCKTHREAD_MUTEX_HPP
namespace Libsockthread {
class Mutex {
@@ -50,4 +50,4 @@ namespace Libsockthread {
};
}
#endif // MUTEX_HPP
#endif // LIBSOCKTHREAD_MUTEX_HPP

View File

@@ -0,0 +1 @@
#undef WINTHREAD

View File

@@ -31,17 +31,57 @@
#include "platform.hpp"
#include "socket.hpp"
size_t Socket::total = 0; // the total number of sockets in use
/*
* Constructs an IPv4 TCP socket
*/
Socket::Socket(void)
{
++total;
#ifdef WINSOCK
if (total == 1)
winsock_startup();
#endif
socket(PF_INET, SOCK_STREAM);
}
/*
* Constructs a socket
*
* domain - either PF_INET or PF_INET6
* type - either SOCK_STREAM or SOCK_DGRAM
*/
Socket::Socket(int domain, int type)
{
++total;
#ifdef WINSOCK
if (total == 1)
winsock_startup();
#endif
socket(domain, type);
}
/*
* Destroys a socket
*/
Socket::~Socket(void)
{
total--;
// TODO: finish me
}
/*
* Creates a socket
*
* domain - either PF_INET or PF_INET6
* type - either SOCK_STREAM or SOCK_DGRAM
*/
Socket::Socket(int type)
void Socket::create_socket(int domain, int type)
{
#ifdef WINSOCK
winsock_startup();
#endif
sock = socket(PF_INET, type, 0);
assert((domain == PF_INET || domain == PF_INET6) &&
(type == SOCK_STREAM || type == SOCK_DGRAM));
sock = socket(domain, type, 0);
#ifdef WINSOCK
if (sock == INVALID_SOCKET)
throw Socket_error(sam_winsock_strerror(WSAGetLastError()));

View File

@@ -28,13 +28,15 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SOCKET_HPP
#define SOCKET_HPP
#ifndef LIBSOCKTHREAD_SOCKET_HPP
#define LIBSOCKTHREAD_SOCKET_HPP
namespace Libsockthread {
class Socket {
public:
Socket(int type); // throws Socket error
Socket(void); // throws socket error
Socket(int domain, int type); // throws Socket_error
~Socket(void);
void func(void);
private:
@@ -47,7 +49,10 @@ namespace Libsockthread {
#else
typedef int socket_t;
#endif
void create_socket(int domain, int type); // throws Socket_error
socket_t sock;
static size_t total;
};
class Socket_error : public runtime_error {
@@ -57,4 +62,4 @@ namespace Libsockthread {
};
}
#endif // MUTEX_HPP
#endif // LIBSOCKTHREAD_SOCKET_HPP

View File

@@ -30,8 +30,17 @@
// Modelled after JThread by Jori Liesenborgs
#include <cassert>
#include "platform.hpp"
#ifdef WINTHREAD
#include <windows.h>
#else
#include <pthread.h>
#endif
using namespace std;
#include "mutex.hpp"
#include "thread.hpp"
using namespace Libsockthread;
/*
* Gets the return value of a finished thread
@@ -97,10 +106,10 @@ void Thread::start(void)
#endif
continue_m.lock();
#ifdef WINTHREAD
handle = CreateThread(NULL, 0, &the_thread, this, 0, &id);
assert(handle != NULL);
handle = CreateThread(0, 0, &the_thread, this, 0, &id);
assert(handle != 0);
#else
int rc = pthread_create(&id, NULL, &the_thread, this);
int rc = pthread_create(&id, 0, &the_thread, this);
assert(rc == 0);
#endif
// Wait until `running' is set
@@ -118,17 +127,73 @@ void Thread::start(void)
*/
void* Thread::the_thread(void *param)
{
Thread* t = dynamic_cast<Thread*>(param);
Thread* t = static_cast<Thread*>(param);
t->running_m.lock();
t->running = true;
t->running_m.unlock();
// wait until we can continue
t->continue_m.lock();
t->continue_m.unlock();
void* ret = t->execute();
void* ret = t->thread();
t->running_m.lock();
t->running = false;
t->retval = ret;
t->running_m.unlock();
return 0;
}
#ifdef UNIT_TEST
// g++ -Wall -c mutex.cpp -o mutex.o
// g++ -Wall -DUNIT_TEST -c thread.cpp -o thread.o
// g++ -Wall -DUNIT_TEST mutex.o thread.o -o thread -lpthread
#include <iostream>
int main(void)
{
class Thread_test : public Thread
{
public:
Thread_test(int testval)
: testval(testval) { }
int get_testval(void)
{
testval_m.lock();
int rc = testval;
testval_m.unlock();
return rc;
}
void *thread(void)
{
// just do something
while (true) {
testval_m.lock();
++testval;
testval_m.unlock();
}
return 0;
}
private:
int testval;
Mutex testval_m;
};
Thread_test t1(1);
t1.start();
Thread_test t2(1000000);
t2.start();
Thread_test t3(-1000000);
t3.start();
while (true) {
if (t1.is_running())
cout << "t1 is running..." << t1.get_testval() << '\n';
if (t2.is_running())
cout << "t2 is running..." << t2.get_testval() << '\n';
if (t3.is_running())
cout << "t3 is running..." << t3.get_testval() << '\n';
}
return 0;
}
#endif // UNIT_TEST

View File

@@ -30,8 +30,8 @@
// Modelled after JThread by Jori Liesenborgs
#ifndef THREAD_HPP
#define THREAD_HPP
#ifndef LIBSOCKTHREAD_THREAD_HPP
#define LIBSOCKTHREAD_THREAD_HPP
namespace Libsockthread {
class Thread {
@@ -41,12 +41,11 @@ namespace Libsockthread {
virtual ~Thread(void)
{ kill(); }
virtual void *execute(void) = 0;
void* get_retval(void);
bool is_running(void);
void kill(void);
void start(void);
virtual void *thread(void) = 0;
private:
#ifdef WINTHREAD
static DWORD WINAPI the_thread(void* param);
@@ -56,11 +55,11 @@ namespace Libsockthread {
static void* the_thread(void* param);
pthread_t id;
#endif
Mutex continue_m;
void *retval;
bool running;
Mutex running_m;
Mutex continue_m;
};
}
#endif // THREAD_HPP
#endif // LIBSOCKTHREAD_THREAD_HPP

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the author nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <ctime>
#include <string>
using namespace std;
#include "time.hpp"
using namespace Libsockthread;
/*
* Converts the time to an ISO 8601 standard time and date and puts it in a string
* Example: 2004-07-01 19:03:47Z
*/
string& Time::utc(string &s) const
{
struct tm* tm;
tm = gmtime(&unixtime);
char t[21];
strftime(t, sizeof t, "%Y-%m-%d %H:%M:%SZ", tm);
return s = t;
}
/*
* Converts the time to an ISO 8601 standard date and puts it in a string
* Example: 2004-07-01Z
*/
string& Time::utc_date(string &s) const
{
struct tm* tm;
tm = gmtime(&unixtime);
char t[12];
strftime(t, sizeof t, "%Y-%m-%dZ", tm);
return s = t;
}
/*
* Converts the time to an ISO 8601 standard time and puts it in a string
* Example: 19:03:47Z
*/
string& Time::utc_time(string &s) const
{
struct tm* tm;
tm = gmtime(&unixtime);
char t[10];
strftime(t, sizeof t, "%H:%M:%SZ", tm);
return s = t;
}
#ifdef UNIT_TEST
// g++ -Wall -DUNIT_TEST time.cpp -o time
#include <iostream>
int main(void)
{
Time t;
string s;
cout << "Current date and time is " << t.utc(s) << '\n';
cout << "Current date is " << t.utc_date(s) << '\n';
cout << "Current time is " << t.utc_time(s) << '\n';
return 0;
}
#endif // UNIT_TEST

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the author nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LIBSOCKTHREAD_TIME_HPP
#define LIBSOCKTHREAD_TIME_HPP
namespace Libsockthread {
class Time {
public:
Time(void) { now(); }
void now(void) { unixtime = time(0); }
string& utc(string &s) const;
string& utc_date(string &s) const;
string& utc_time(string &s) const;
private:
time_t unixtime;
};
}
#endif // LIBSOCKTHREAD_TIME_HPP