Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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

  • Loading branch information...
commit 7a6f96e4b257ae599d7f7444eb5ac5c90d3a58e2 1 parent d7d1a10
Martin Berends authored August 08, 2011
25  c/src/threads.c
... ...
@@ -0,0 +1,25 @@
  1
+/* threads.c */
  2
+
  3
+/* Abstract the different threading interfaces present in different */
  4
+/* operating systems.  This library closely resembles pthreads, so */
  5
+/* is a very thin wrapper on Posix systems, and does a lightweight */
  6
+/* emulation on the others. */
  7
+
  8
+#include "threads.h"  /* thread_create */
  9
+
  10
+/* thread_create */
  11
+int
  12
+thread_create(struct thread_info * info, void * (* function)(void *), void * arg )
  13
+{
  14
+    int status;
  15
+    #if defined( __APPLE__ ) || defined( __linux__ )
  16
+        status = pthread_create(&info->thread_id, NULL, function, arg);
  17
+    #elif defined( _WIN32 )
  18
+        info->threadhandle = CreateThread(NULL, 0,
  19
+            (LPTHREAD_START_ROUTINE) function, arg, 0, NULL);
  20
+        status = (info->threadhandle == NULL);
  21
+    #endif
  22
+    return status;
  23
+}
  24
+
  25
+/* end of threads.c */
21  c/src/threads.h
... ...
@@ -0,0 +1,21 @@
  1
+/* threads.h */
  2
+
  3
+#if defined( __APPLE__ ) || defined( __linux__ )
  4
+    #include <pthread.h>
  5
+#elif defined( _WIN32 )
  6
+    #include <windows.h>
  7
+#endif
  8
+
  9
+/* thread_info */
  10
+struct thread_info {
  11
+    #if defined( __APPLE__ ) || defined( __linux__ )
  12
+        pthread_t thread_id;
  13
+    #elif defined( _WIN32 )
  14
+        HANDLE threadhandle;
  15
+    #endif
  16
+};
  17
+
  18
+int thread_create(struct thread_info * info, void * (* function)(void *), void * arg );
  19
+int thread_join(struct thread_info * info);
  20
+
  21
+/* end of threads.h */
58  c/src/timing.c
... ...
@@ -0,0 +1,58 @@
  1
+/* timing.c */
  2
+
  3
+/* This timing library abstracts the different ways that operating */
  4
+/* systems give the current time and do delays. */
  5
+
  6
+#ifdef _WIN32
  7
+    #include <windows.h>   /* FILETIME GetSystemTimeAsFileTime */
  8
+#else
  9
+    #include <stdlib.h>    /* NULL */
  10
+    #include <sys/time.h>  /* gettimeofday */
  11
+#endif
  12
+#include "timing.h"
  13
+
  14
+
  15
+/* gettime */
  16
+/* Returns UTC seconds from 1970-01-01 in the upper 44 bits and */
  17
+/* microseconds in the lower 20 bits of a 64 bit value. */
  18
+long long
  19
+gettime()
  20
+{
  21
+    int microseconds;
  22
+    long long seconds, result;
  23
+    #ifdef _WIN32
  24
+        FILETIME time1;
  25
+        GetSystemTimeAsFileTime(&time1);
  26
+        seconds = (((long long)time1.dwHighDateTime) << 32)
  27
+                             | time1.dwLowDateTime;
  28
+        seconds -= 11644473600; /* from 1601-01-01 to 1970-01-01 */
  29
+        microseconds = (seconds % 10000000)/10; seconds /= 10000000;
  30
+    #else
  31
+        struct timeval time1;
  32
+        gettimeofday(&time1, NULL);
  33
+        seconds      = time1.tv_sec;
  34
+        microseconds = time1.tv_usec;
  35
+    #endif
  36
+    return (seconds << 20) | microseconds;
  37
+}
  38
+
  39
+
  40
+/* millisleep */
  41
+void
  42
+millisleep(int milliseconds)
  43
+{
  44
+    #ifdef _WIN32
  45
+        Sleep(milliseconds);
  46
+    #else
  47
+        struct timespec request, remainder;
  48
+        request.tv_sec  = milliseconds / 1000;
  49
+        request.tv_nsec = (milliseconds % 1000) * 1000000;
  50
+        nanosleep(&request, &remainder);  /* ignore possible errors */
  51
+    #endif
  52
+}
  53
+
  54
+/* See also: */
  55
+/* UTC, TAI, and UNIX time http://cr.yp.to/proto/utctai.html */
  56
+/* Online time converter: http://www.silisoftware.com/tools/date.php */
  57
+
  58
+/* end of timing.c */
6  c/src/timing.h
... ...
@@ -0,0 +1,6 @@
  1
+/* timing.h */
  2
+
  3
+long long gettime();    /* 44 bits Unix seconds, 20 bits microseconds */
  4
+void millisleep(int milliseconds);
  5
+
  6
+/* end of timing.h */
6  c/t/01-toolchain/01c-threads.c → c/t/01-toolchain/01c-osthreads.c
... ...
@@ -1,4 +1,4 @@
1  
-/* 01c-threads.c */
  1
+/* 01c-osthreads.c */
2 2
 /* Check that threading in the operating system and libraries is ok */
3 3
 
4 4
 #include <assert.h>   /* assert */
@@ -205,11 +205,11 @@ tests5_6charcount()
205 205
 int
206 206
 main(int arg, char * argv[])
207 207
 {
208  
-    diag("01c-threads");
  208
+    diag("01c-osthreads");
209 209
     plan(5);
210 210
     tests1_4sleeps();  /* two threads that sleep and print */
211 211
     tests5_6charcount();  /* four threads returning integers */
212 212
     return 0;
213 213
 }
214 214
 
215  
-/* end of 01c-threads.c */
  215
+/* end of 01c-osthreads.c */
59  c/t/02-components/02a-threads.c
... ...
@@ -0,0 +1,59 @@
  1
+/* 02a-threads.c */
  2
+
  3
+#include <assert.h>   /* assert */
  4
+#include "../../src/threads.h"
  5
+#include "../../src/timing.h"
  6
+#include "../Test.h"  /* diag is plan */
  7
+
  8
+#ifdef __cplusplus
  9
+extern "C" {
  10
+#endif
  11
+
  12
+
  13
+/* test1args */
  14
+struct test1args {
  15
+    int milliseconds;
  16
+    char * message;
  17
+};
  18
+
  19
+
  20
+/* test1func */
  21
+void *
  22
+test1func(void * arg)
  23
+{
  24
+    char message[80];
  25
+    struct test1args * targ;  targ = (struct test1args *) arg;
  26
+    sprintf(message, "from %s sleep", targ->message);
  27
+    millisleep(targ->milliseconds);
  28
+    ok(1, message);
  29
+    return NULL;
  30
+}
  31
+
  32
+
  33
+/* tests1_1 */
  34
+void
  35
+tests1_1(void)
  36
+{
  37
+    struct thread_info tinfo[2];
  38
+    struct test1args   targs[2];
  39
+    targs[0].milliseconds = 10; targs[0].message = "10ms";
  40
+    targs[1].milliseconds = 20; targs[1].message = "20ms";
  41
+    ok( thread_create(tinfo+0, test1func, targs+0) == 0, "start 10ms sleep" );
  42
+    ok( thread_create(tinfo+1, test1func, targs+1) == 0, "start 20ms sleep" );
  43
+    millisleep(75);
  44
+}
  45
+
  46
+
  47
+/* main */
  48
+int main(int argc, char *argv[])
  49
+{
  50
+    diag("02a-threads");
  51
+    plan(4);
  52
+    tests1_1();
  53
+}
  54
+
  55
+#ifdef __cplusplus
  56
+}
  57
+#endif
  58
+
  59
+/* end of 02a-threads.c */
8  c/t/02-components/02a-hashtable.c → c/t/02-components/02b-hashtable.c
... ...
@@ -1,4 +1,4 @@
1  
-/* 02a-hashtable.c */
  1
+/* 02b-hashtable.c */
2 2
 /* Create several hashes and store, fetch and delete a large number */
3 3
 /* of random data values.  Count the number of such random operations */
4 4
 /* (not exactly repeatable) that can be performed in a 10 second */
@@ -10,7 +10,7 @@
10 10
 #include <stdlib.h>   /* malloc */
11 11
 #include <string.h>   /* memmove strlen */
12 12
 #include "../../src/hashtable.h"
13  
-#include "../Test.h"  /* diag is plan */
  13
+#include "../Test.h"  /* diag is_ii plan */
14 14
 
15 15
 /* The number of allocations is O((STRINGCOUNT ** 2) * MAXKEYLENGTH), */
16 16
 /* so be careful when increasing it.  5000 strings use 250MiB. */
@@ -97,7 +97,7 @@ int main(int argc, char *argv[])
97 97
         value_bytes = 0, entrynumber, collisions = 0, delete_count;
98 98
     char * source, * destination, * value;
99 99
 
100  
-    diag("02a-hashtable");
  100
+    diag("02b-hashtable");
101 101
     plan(4);
102 102
     hashtable = hashtable_new();
103 103
     srand(seed);  /* TODO: get a portable seed from for example current time */
@@ -160,4 +160,4 @@ int main(int argc, char *argv[])
160 160
 }
161 161
 #endif
162 162
 
163  
-/* end of 02a-hashtable.c */
  163
+/* end of 02b-hashtable.c */
31  c/tools/build/Makefile.in
@@ -6,9 +6,9 @@
6 6
 
7 7
 # Targets that do not produce files (tells the make utility to skip
8 8
 # looking for such non existent files).
9  
-.PHONY: all clean realclean test test01 test02
  9
+.PHONY: all clean help realclean test test01 test02
10 10
 
11  
-# Configure.c replaces the words between @ signs.
  11
+# Configure.c replaces words it recognizes between the @ signs.
12 12
 CC        = @cc@
13 13
 EXE       = @exe@
14 14
 O         = @outfile@
@@ -27,23 +27,23 @@ t/01-toolchain/01b-timing.exe: t/01-toolchain/01b-timing.c t/Test.h
27 27
 	$(CC) $(O) t/01-toolchain/01b-timing.exe t/01-toolchain/01b-timing.c
28 28
 	-$(RM_RF) 01b-timing.obj
29 29
 
30  
-t/01-toolchain/01c-threads.exe: t/01-toolchain/01c-threads.c t/Test.h
31  
-	$(CC) $(THREADS) $(O) t/01-toolchain/01c-threads.exe t/01-toolchain/01c-threads.c
32  
-	-$(RM_RF) 01c-threads.obj
  30
+t/01-toolchain/01c-osthreads.exe: t/01-toolchain/01c-osthreads.c t/Test.h
  31
+	$(CC) $(THREADS) $(O) t/01-toolchain/01c-osthreads.exe t/01-toolchain/01c-osthreads.c
  32
+	-$(RM_RF) 01c-osthreads.obj
33 33
 
34 34
 t/02-components/02a-threads.exe: t/02-components/02a-threads.c \
35  
-		src/threads.h src/threads.c t/Test.h
36  
-	$(CC) $(O) t/02-components/02a-threads.exe src/threads.c t/02-components/02a-threads.c
  35
+		src/threads.h src/threads.c src/timing.c src/timing.h t/Test.h
  36
+	$(CC) $(THREADS) $(O) t/02-components/02a-threads.exe src/threads.c src/timing.c t/02-components/02a-threads.c
37 37
 	-$(RM_RF) threads.obj 02a-threads.obj
38 38
 
39  
-t/02-components/02a-hashtable.exe: t/02-components/02a-hashtable.c \
  39
+t/02-components/02b-hashtable.exe: t/02-components/02b-hashtable.c \
40 40
 		src/hashtable.h src/hashtable.c t/Test.h
41  
-	$(CC) $(O) t/02-components/02a-hashtable.exe src/hashtable.c t/02-components/02a-hashtable.c
42  
-	-$(RM_RF) hashtable.obj 02a-hashtable.obj
  41
+	$(CC) $(O) t/02-components/02b-hashtable.exe src/hashtable.c t/02-components/02b-hashtable.c
  42
+	-$(RM_RF) hashtable.obj 02b-hashtable.obj
43 43
 
44  
-t/02-components/02b-heapmanager.exe: t/02-components/02b-heapmanager.c \
  44
+t/02-components/02c-heapmanager.exe: t/02-components/02c-heapmanager.c \
45 45
 		src/heapmanager.h src/heapmanager.c t/Test.h
46  
-	$(CC) $(O) t/02-components/02b-heapmanager.exe src/heapmanager.c t/02-components/02b-heapmanager.c
  46
+	$(CC) $(O) t/02-components/02c-heapmanager.exe src/heapmanager.c t/02-components/02c-heapmanager.c
47 47
 	-$(RM_RF) heapmanager.obj 02b-heapmanager.obj
48 48
 
49 49
 tools/build/prove$(EXE): tools/build/prove.c
@@ -58,11 +58,12 @@ test: test01 test02
58 58
 # functions needed by the rest of the code.  It is generally unnecessary
59 59
 # to run this test, but is useful when troubleshooting.
60 60
 test01: t/01-toolchain/01a-cc.exe t/01-toolchain/01b-timing.exe \
61  
-		t/01-toolchain/01c-threads.exe tools/build/prove$(EXE)
  61
+		t/01-toolchain/01c-osthreads.exe tools/build/prove$(EXE)
62 62
 	tools/build/prove -e "" --ext ".exe" t/01-toolchain
63 63
 
64 64
 # The test02 target validates the internal libraries of 6model/c
65  
-test02: t/02-components/02a-hashtable.exe tools/build/prove$(EXE)
  65
+test02: t/02-components/02a-threads.exe \
  66
+		t/02-components/02b-hashtable.exe tools/build/prove$(EXE)
66 67
 	tools/build/prove -e "" --ext ".exe" t/02-components
67 68
 
68 69
 # Miscellaneous targets
@@ -73,7 +74,7 @@ clean:
73 74
 		t/02-components/*.exe t/02-components/*~
74 75
 
75 76
 realclean: clean
76  
-	perl -MExtUtils::Command -e rm_f Makefile
  77
+	$(RM_RF) Makefile
77 78
 
78 79
 help:
79 80
 	@echo In this 6model/c directory you can make the following targets:

0 notes on commit 7a6f96e

Please sign in to comment.
Something went wrong with that request. Please try again.