1 /*
2  * Copyright 2008 Google Inc. All Rights Reserved.
3  * Author: md@google.com (Michael Davidson)
4  */
5 #define _GNU_SOURCE
6 
7 #include <stdio.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <sched.h>
11 #include <pthread.h>
12 
13 #include "logging.h"
14 #include "threads.h"
15 
16 #define MAX_CPUS	CPU_SETSIZE
17 #define	MAX_THREADS	MAX_CPUS
18 
19 typedef struct thread {
20 	pthread_t	thread;
21 	cpu_set_t	cpus;
22 	thread_func_t	func;
23 	void		*arg;
24 } thread_t;
25 
26 static thread_t	threads[MAX_THREADS];
27 static int	num_threads;
28 
29 
30 /*
31  * Helper function to run a thread on a specific set of CPUs.
32  */
run_thread(void * arg)33 static void *run_thread(void *arg)
34 {
35 	thread_t	*thread = arg;
36 	void		*result;
37 
38 	if (sched_setaffinity(0, sizeof thread->cpus, &thread->cpus) < 0)
39 		WARN(errno, "sched_setaffinity() failed");
40 
41 	result = thread->func(thread->arg);
42 
43 	return result;
44 }
45 
46 
47 /*
48  * Create a set of threads each of which is bound to one of
49  * the CPUs specified by cpus.
50  * Returns the number of threads created.
51  */
create_per_cpu_threads(cpu_set_t * cpus,thread_func_t func,void * arg)52 int create_per_cpu_threads(cpu_set_t *cpus, thread_func_t func, void *arg)
53 {
54 	int	cpu;
55 
56 	for (cpu = 0; cpu < MAX_CPUS; cpu++) {
57 		int		err;
58 		thread_t	*thread;
59 		if (!CPU_ISSET(cpu, cpus))
60 			continue;
61 		if (num_threads >= MAX_THREADS)
62 			break;
63 
64 		thread		= &threads[num_threads++];
65 		thread->func	= func;
66 		thread->arg	= arg;
67 		CPU_ZERO(&thread->cpus);
68 		CPU_SET(cpu, &thread->cpus);
69 
70 		err = pthread_create(&thread->thread, NULL, run_thread, thread);
71 		if (err) {
72 			WARN(err, "pthread_create() failed");
73 			--num_threads;
74 			break;
75 		}
76 	}
77 
78 	return num_threads;
79 }
80 
81 
82 /*
83  * Create nthreads threads.
84  * Returns the number of threads created.
85  */
create_threads(int nthreads,thread_func_t func,void * arg)86 int create_threads(int nthreads, thread_func_t func, void *arg)
87 {
88 	if (nthreads > MAX_THREADS)
89 		nthreads = MAX_THREADS;
90 
91 	while (--nthreads >= 0) {
92 		int		err;
93 		thread_t	*thread;
94 
95 		thread		= &threads[num_threads++];
96 		thread->func	= func;
97 		thread->arg	= arg;
98 		CPU_ZERO(&thread->cpus);
99 
100 		err = pthread_create(&thread->thread, NULL, func, arg);
101 		if (err) {
102 			WARN(err, "pthread_create() failed");
103 			--num_threads;
104 			break;
105 		}
106 	}
107 
108 	return num_threads;
109 }
110 
111 
112 /*
113  * Join with the set of previsouly created threads.
114  */
join_threads(void)115 void join_threads(void)
116 {
117 	while (num_threads > 0)
118 		pthread_join(threads[--num_threads].thread, NULL);
119 }
120 
121