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
19typedef struct thread {
20	pthread_t	thread;
21	cpu_set_t	cpus;
22	thread_func_t	func;
23	void		*arg;
24} thread_t;
25
26static thread_t	threads[MAX_THREADS];
27static int	num_threads;
28
29
30/*
31 * Helper function to run a thread on a specific set of CPUs.
32 */
33static 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 */
52int 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 */
86int 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 */
115void join_threads(void)
116{
117	while (num_threads > 0)
118		pthread_join(threads[--num_threads].thread, NULL);
119}
120
121