The Pedigree Project  0.1
user/applications/thread-test/main.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <errno.h>
21 #include <pthread.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <sys/klog.h>
25 #include <sys/time.h>
26 #include <unistd.h>
27 
28 #include <list>
29 
30 #define LOOPS 1024 // 10000000
31 
32 // Modified from http://www.alexonlinux.com/do-you-need-mutex-to-protect-int
33 // Uses mutexes or spinlocks
34 
35 using namespace std;
36 
37 list<int> the_list;
38 
39 // #define USE_SPINLOCK
40 
41 #ifdef USE_SPINLOCK
42 pthread_spinlock_t spinlock;
43 #else
44 pthread_mutex_t mutex;
45 #endif
46 
47 void *consumer(void *ptr)
48 {
49  int i;
50 
51  printf("Consumer TID %lu\n", (unsigned long) ptr);
52 
53  while (1)
54  {
55 #ifdef USE_SPINLOCK
56  pthread_spin_lock(&spinlock);
57 #else
58  pthread_mutex_lock(&mutex);
59 #endif
60 
61  if (the_list.empty())
62  {
63 #ifdef USE_SPINLOCK
64  pthread_spin_unlock(&spinlock);
65 #else
66  pthread_mutex_unlock(&mutex);
67 #endif
68  break;
69  }
70 
71  i = the_list.front();
72  the_list.pop_front();
73 
74 #ifdef USE_SPINLOCK
75  pthread_spin_unlock(&spinlock);
76 #else
77  pthread_mutex_unlock(&mutex);
78 #endif
79  }
80 
81  return NULL;
82 }
83 
84 int main()
85 {
86  int i;
87  pthread_t thr1, thr2;
88  struct timeval tv1, tv2;
89 
90 #ifdef USE_SPINLOCK
91  pthread_spin_init(&spinlock, 0);
92 #else
93  pthread_mutex_init(&mutex, NULL);
94 #endif
95 
96  // syslog used to split up debug logs.
97  klog(LOG_INFO, "TEST 0");
98 
99  printf("Locking without any contention...\n");
100  pthread_mutex_t contention_mutex;
101  pthread_mutex_init(&contention_mutex, 0);
102  pthread_mutex_lock(&contention_mutex);
103  printf("Acquired\n");
104  pthread_mutex_unlock(&contention_mutex);
105  printf("Released!\n");
106 
107  klog(LOG_INFO, "TEST 1");
108 
109  printf("Creating a recursive lock!\n");
110  pthread_mutex_t recursive;
111  pthread_mutexattr_t attr;
112  pthread_mutexattr_init(&attr);
113  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
114  pthread_mutex_init(&recursive, &attr);
115  printf("Testing recursion...\n");
116  pthread_mutex_lock(&recursive);
117  pthread_mutex_lock(&recursive);
118  pthread_mutex_lock(&recursive);
119  printf("Locked OK, testing unlock...\n");
120  pthread_mutex_unlock(&recursive);
121  pthread_mutex_unlock(&recursive);
122  pthread_mutex_unlock(&recursive);
123  printf("Testing re-acquire...\n");
124  pthread_mutex_lock(&recursive);
125  printf("OK!\n");
126 
127  klog(LOG_INFO, "TEST 2");
128  printf("Locking with deadlock\n");
129  pthread_mutex_t deadlock_mutex;
130  errno = 0;
131  pthread_mutex_init(&deadlock_mutex, 0);
132  i = pthread_mutex_lock(&deadlock_mutex);
133  printf("First lock: %d (%s)\n", i, strerror(errno));
134  i = pthread_mutex_lock(&deadlock_mutex);
135  if (errno != EDEADLK)
136  printf("Didn't get EDEADLK!\n");
137  printf("Second lock: %d (%s)\n", i, strerror(errno));
138  pthread_mutex_unlock(&deadlock_mutex);
139 
140  // Creating the list content...
141  for (i = 0; i < LOOPS; i++)
142  the_list.push_back(i);
143 
144  // Measuring time before starting the threads...
145  gettimeofday(&tv1, NULL);
146 
147  klog(LOG_INFO, "TEST 3");
148  pthread_create(&thr1, NULL, consumer, (void *) 1);
149  pthread_create(&thr2, NULL, consumer, (void *) 2);
150 
151  pthread_join(thr1, NULL);
152  pthread_join(thr2, NULL);
153  klog(LOG_INFO, "TEST 4");
154 
155  // Measuring time after threads finished...
156  gettimeofday(&tv2, NULL);
157 
158  if (tv1.tv_usec > tv2.tv_usec)
159  {
160  tv2.tv_sec--;
161  tv2.tv_usec += 1000000;
162  }
163 
164  printf(
165  "Result - %ld.%ld\n", tv2.tv_sec - tv1.tv_sec,
166  tv2.tv_usec - tv1.tv_usec);
167 
168 #ifdef USE_SPINLOCK
169  pthread_spin_destroy(&spinlock);
170 #else
171  pthread_mutex_destroy(&mutex);
172 #endif
173 
174  return 0;
175 }