Permalink
Browse files

[6model/c] add a generic threads library with simple tests

  • Loading branch information...
mberends committed Aug 8, 2011
1 parent d7d1a10 commit 7a6f96e4b257ae599d7f7444eb5ac5c90d3a58e2
View
@@ -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 */
View
@@ -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 */
View
@@ -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 */
View
@@ -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 */
@@ -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 */
@@ -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 */
@@ -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. */
@@ -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 */
@@ -160,4 +160,4 @@ int main(int argc, char *argv[])
}
#endif
-/* end of 02a-hashtable.c */
+/* end of 02b-hashtable.c */
View
@@ -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@
@@ -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
@@ -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
@@ -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:

0 comments on commit 7a6f96e

Please sign in to comment.