Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[6model/c] add a generic threads library with simple tests
  • Loading branch information
mberends committed Aug 8, 2011
1 parent d7d1a10 commit 7a6f96e
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 22 deletions.
25 changes: 25 additions & 0 deletions c/src/threads.c
@@ -0,0 +1,25 @@
/* threads.c */

/* Abstract the different threading interfaces present in different */
/* operating systems. This library closely resembles pthreads, so */
/* is a very thin wrapper on Posix systems, and does a lightweight */
/* emulation on the others. */

#include "threads.h" /* thread_create */

/* thread_create */
int
thread_create(struct thread_info * info, void * (* function)(void *), void * arg )
{
int status;
#if defined( __APPLE__ ) || defined( __linux__ )
status = pthread_create(&info->thread_id, NULL, function, arg);
#elif defined( _WIN32 )
info->threadhandle = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) function, arg, 0, NULL);
status = (info->threadhandle == NULL);
#endif
return status;
}

/* end of threads.c */
21 changes: 21 additions & 0 deletions c/src/threads.h
@@ -0,0 +1,21 @@
/* threads.h */

#if defined( __APPLE__ ) || defined( __linux__ )
#include <pthread.h>
#elif defined( _WIN32 )
#include <windows.h>
#endif

/* thread_info */
struct thread_info {
#if defined( __APPLE__ ) || defined( __linux__ )
pthread_t thread_id;
#elif defined( _WIN32 )
HANDLE threadhandle;
#endif
};

int thread_create(struct thread_info * info, void * (* function)(void *), void * arg );
int thread_join(struct thread_info * info);

/* end of threads.h */
58 changes: 58 additions & 0 deletions c/src/timing.c
@@ -0,0 +1,58 @@
/* timing.c */

/* This timing library abstracts the different ways that operating */
/* systems give the current time and do delays. */

#ifdef _WIN32
#include <windows.h> /* FILETIME GetSystemTimeAsFileTime */
#else
#include <stdlib.h> /* NULL */
#include <sys/time.h> /* gettimeofday */
#endif
#include "timing.h"


/* gettime */
/* Returns UTC seconds from 1970-01-01 in the upper 44 bits and */
/* microseconds in the lower 20 bits of a 64 bit value. */
long long
gettime()
{
int microseconds;
long long seconds, result;
#ifdef _WIN32
FILETIME time1;
GetSystemTimeAsFileTime(&time1);
seconds = (((long long)time1.dwHighDateTime) << 32)
| time1.dwLowDateTime;
seconds -= 11644473600; /* from 1601-01-01 to 1970-01-01 */
microseconds = (seconds % 10000000)/10; seconds /= 10000000;
#else
struct timeval time1;
gettimeofday(&time1, NULL);
seconds = time1.tv_sec;
microseconds = time1.tv_usec;
#endif
return (seconds << 20) | microseconds;
}


/* millisleep */
void
millisleep(int milliseconds)
{
#ifdef _WIN32
Sleep(milliseconds);
#else
struct timespec request, remainder;
request.tv_sec = milliseconds / 1000;
request.tv_nsec = (milliseconds % 1000) * 1000000;
nanosleep(&request, &remainder); /* ignore possible errors */
#endif
}

/* See also: */
/* UTC, TAI, and UNIX time http://cr.yp.to/proto/utctai.html */
/* Online time converter: http://www.silisoftware.com/tools/date.php */

/* end of timing.c */
6 changes: 6 additions & 0 deletions c/src/timing.h
@@ -0,0 +1,6 @@
/* timing.h */

long long gettime(); /* 44 bits Unix seconds, 20 bits microseconds */
void millisleep(int milliseconds);

/* end of timing.h */
@@ -1,4 +1,4 @@
/* 01c-threads.c */
/* 01c-osthreads.c */
/* Check that threading in the operating system and libraries is ok */

#include <assert.h> /* assert */
Expand Down Expand Up @@ -205,11 +205,11 @@ tests5_6charcount()
int
main(int arg, char * argv[])
{
diag("01c-threads");
diag("01c-osthreads");
plan(5);
tests1_4sleeps(); /* two threads that sleep and print */
tests5_6charcount(); /* four threads returning integers */
return 0;
}

/* end of 01c-threads.c */
/* end of 01c-osthreads.c */
59 changes: 59 additions & 0 deletions c/t/02-components/02a-threads.c
@@ -0,0 +1,59 @@
/* 02a-threads.c */

#include <assert.h> /* assert */
#include "../../src/threads.h"
#include "../../src/timing.h"
#include "../Test.h" /* diag is plan */

#ifdef __cplusplus
extern "C" {
#endif


/* test1args */
struct test1args {
int milliseconds;
char * message;
};


/* test1func */
void *
test1func(void * arg)
{
char message[80];
struct test1args * targ; targ = (struct test1args *) arg;
sprintf(message, "from %s sleep", targ->message);
millisleep(targ->milliseconds);
ok(1, message);
return NULL;
}


/* tests1_1 */
void
tests1_1(void)
{
struct thread_info tinfo[2];
struct test1args targs[2];
targs[0].milliseconds = 10; targs[0].message = "10ms";
targs[1].milliseconds = 20; targs[1].message = "20ms";
ok( thread_create(tinfo+0, test1func, targs+0) == 0, "start 10ms sleep" );
ok( thread_create(tinfo+1, test1func, targs+1) == 0, "start 20ms sleep" );
millisleep(75);
}


/* main */
int main(int argc, char *argv[])
{
diag("02a-threads");
plan(4);
tests1_1();
}

#ifdef __cplusplus
}
#endif

/* end of 02a-threads.c */
@@ -1,4 +1,4 @@
/* 02a-hashtable.c */
/* 02b-hashtable.c */
/* Create several hashes and store, fetch and delete a large number */
/* of random data values. Count the number of such random operations */
/* (not exactly repeatable) that can be performed in a 10 second */
Expand All @@ -10,7 +10,7 @@
#include <stdlib.h> /* malloc */
#include <string.h> /* memmove strlen */
#include "../../src/hashtable.h"
#include "../Test.h" /* diag is plan */
#include "../Test.h" /* diag is_ii plan */

/* The number of allocations is O((STRINGCOUNT ** 2) * MAXKEYLENGTH), */
/* so be careful when increasing it. 5000 strings use 250MiB. */
Expand Down Expand Up @@ -97,7 +97,7 @@ int main(int argc, char *argv[])
value_bytes = 0, entrynumber, collisions = 0, delete_count;
char * source, * destination, * value;

diag("02a-hashtable");
diag("02b-hashtable");
plan(4);
hashtable = hashtable_new();
srand(seed); /* TODO: get a portable seed from for example current time */
Expand Down Expand Up @@ -160,4 +160,4 @@ int main(int argc, char *argv[])
}
#endif

/* end of 02a-hashtable.c */
/* end of 02b-hashtable.c */
31 changes: 16 additions & 15 deletions c/tools/build/Makefile.in
Expand Up @@ -6,9 +6,9 @@

# Targets that do not produce files (tells the make utility to skip
# looking for such non existent files).
.PHONY: all clean realclean test test01 test02
.PHONY: all clean help realclean test test01 test02

# Configure.c replaces the words between @ signs.
# Configure.c replaces words it recognizes between the @ signs.
CC = @cc@
EXE = @exe@
O = @outfile@
Expand All @@ -27,23 +27,23 @@ t/01-toolchain/01b-timing.exe: t/01-toolchain/01b-timing.c t/Test.h
$(CC) $(O) t/01-toolchain/01b-timing.exe t/01-toolchain/01b-timing.c
-$(RM_RF) 01b-timing.obj

t/01-toolchain/01c-threads.exe: t/01-toolchain/01c-threads.c t/Test.h
$(CC) $(THREADS) $(O) t/01-toolchain/01c-threads.exe t/01-toolchain/01c-threads.c
-$(RM_RF) 01c-threads.obj
t/01-toolchain/01c-osthreads.exe: t/01-toolchain/01c-osthreads.c t/Test.h
$(CC) $(THREADS) $(O) t/01-toolchain/01c-osthreads.exe t/01-toolchain/01c-osthreads.c
-$(RM_RF) 01c-osthreads.obj

t/02-components/02a-threads.exe: t/02-components/02a-threads.c \
src/threads.h src/threads.c t/Test.h
$(CC) $(O) t/02-components/02a-threads.exe src/threads.c t/02-components/02a-threads.c
src/threads.h src/threads.c src/timing.c src/timing.h t/Test.h
$(CC) $(THREADS) $(O) t/02-components/02a-threads.exe src/threads.c src/timing.c t/02-components/02a-threads.c
-$(RM_RF) threads.obj 02a-threads.obj

t/02-components/02a-hashtable.exe: t/02-components/02a-hashtable.c \
t/02-components/02b-hashtable.exe: t/02-components/02b-hashtable.c \
src/hashtable.h src/hashtable.c t/Test.h
$(CC) $(O) t/02-components/02a-hashtable.exe src/hashtable.c t/02-components/02a-hashtable.c
-$(RM_RF) hashtable.obj 02a-hashtable.obj
$(CC) $(O) t/02-components/02b-hashtable.exe src/hashtable.c t/02-components/02b-hashtable.c
-$(RM_RF) hashtable.obj 02b-hashtable.obj

t/02-components/02b-heapmanager.exe: t/02-components/02b-heapmanager.c \
t/02-components/02c-heapmanager.exe: t/02-components/02c-heapmanager.c \
src/heapmanager.h src/heapmanager.c t/Test.h
$(CC) $(O) t/02-components/02b-heapmanager.exe src/heapmanager.c t/02-components/02b-heapmanager.c
$(CC) $(O) t/02-components/02c-heapmanager.exe src/heapmanager.c t/02-components/02c-heapmanager.c
-$(RM_RF) heapmanager.obj 02b-heapmanager.obj

tools/build/prove$(EXE): tools/build/prove.c
Expand All @@ -58,11 +58,12 @@ test: test01 test02
# functions needed by the rest of the code. It is generally unnecessary
# to run this test, but is useful when troubleshooting.
test01: t/01-toolchain/01a-cc.exe t/01-toolchain/01b-timing.exe \
t/01-toolchain/01c-threads.exe tools/build/prove$(EXE)
t/01-toolchain/01c-osthreads.exe tools/build/prove$(EXE)
tools/build/prove -e "" --ext ".exe" t/01-toolchain

# The test02 target validates the internal libraries of 6model/c
test02: t/02-components/02a-hashtable.exe tools/build/prove$(EXE)
test02: t/02-components/02a-threads.exe \
t/02-components/02b-hashtable.exe tools/build/prove$(EXE)
tools/build/prove -e "" --ext ".exe" t/02-components

# Miscellaneous targets
Expand All @@ -73,7 +74,7 @@ clean:
t/02-components/*.exe t/02-components/*~

realclean: clean
perl -MExtUtils::Command -e rm_f Makefile
$(RM_RF) Makefile

help:
@echo In this 6model/c directory you can make the following targets:
Expand Down

0 comments on commit 7a6f96e

Please sign in to comment.