1/*-
2 *   BSD LICENSE
3 *
4 *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5 *   All rights reserved.
6 *
7 *   Redistribution and use in source and binary forms, with or without
8 *   modification, are permitted provided that the following conditions
9 *   are met:
10 *
11 *     * Redistributions of source code must retain the above copyright
12 *       notice, this list of conditions and the following disclaimer.
13 *     * Redistributions in binary form must reproduce the above copyright
14 *       notice, this list of conditions and the following disclaimer in
15 *       the documentation and/or other materials provided with the
16 *       distribution.
17 *     * Neither the name of Intel Corporation nor the names of its
18 *       contributors may be used to endorse or promote products derived
19 *       from this software without specific prior written permission.
20 *
21 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <errno.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <stdint.h>
38#include <unistd.h>
39#include <sched.h>
40#include <pthread_np.h>
41#include <sys/queue.h>
42#include <sys/thr.h>
43
44#include <rte_debug.h>
45#include <rte_atomic.h>
46#include <rte_launch.h>
47#include <rte_log.h>
48#include <rte_memory.h>
49#include <rte_memzone.h>
50#include <rte_per_lcore.h>
51#include <rte_eal.h>
52#include <rte_per_lcore.h>
53#include <rte_lcore.h>
54
55#include "eal_private.h"
56#include "eal_thread.h"
57
58RTE_DEFINE_PER_LCORE(unsigned, _lcore_id) = LCORE_ID_ANY;
59RTE_DEFINE_PER_LCORE(unsigned, _socket_id) = (unsigned)SOCKET_ID_ANY;
60RTE_DEFINE_PER_LCORE(rte_cpuset_t, _cpuset);
61
62/*
63 * Send a message to a slave lcore identified by slave_id to call a
64 * function f with argument arg. Once the execution is done, the
65 * remote lcore switch in FINISHED state.
66 */
67int
68rte_eal_remote_launch(int (*f)(void *), void *arg, unsigned slave_id)
69{
70	int n;
71	char c = 0;
72	int m2s = lcore_config[slave_id].pipe_master2slave[1];
73	int s2m = lcore_config[slave_id].pipe_slave2master[0];
74
75	if (lcore_config[slave_id].state != WAIT)
76		return -EBUSY;
77
78	lcore_config[slave_id].f = f;
79	lcore_config[slave_id].arg = arg;
80
81	/* send message */
82	n = 0;
83	while (n == 0 || (n < 0 && errno == EINTR))
84		n = write(m2s, &c, 1);
85	if (n < 0)
86		rte_panic("cannot write on configuration pipe\n");
87
88	/* wait ack */
89	do {
90		n = read(s2m, &c, 1);
91	} while (n < 0 && errno == EINTR);
92
93	if (n <= 0)
94		rte_panic("cannot read on configuration pipe\n");
95
96	return 0;
97}
98
99/* set affinity for current thread */
100static int
101eal_thread_set_affinity(void)
102{
103	unsigned lcore_id = rte_lcore_id();
104
105	/* acquire system unique id  */
106	rte_gettid();
107
108	/* update EAL thread core affinity */
109	return rte_thread_set_affinity(&lcore_config[lcore_id].cpuset);
110}
111
112void eal_thread_init_master(unsigned lcore_id)
113{
114	/* set the lcore ID in per-lcore memory area */
115	RTE_PER_LCORE(_lcore_id) = lcore_id;
116
117	/* set CPU affinity */
118	if (eal_thread_set_affinity() < 0)
119		rte_panic("cannot set affinity\n");
120}
121
122/* main loop of threads */
123__attribute__((noreturn)) void *
124eal_thread_loop(__attribute__((unused)) void *arg)
125{
126	char c;
127	int n, ret;
128	unsigned lcore_id;
129	pthread_t thread_id;
130	int m2s, s2m;
131	char cpuset[RTE_CPU_AFFINITY_STR_LEN];
132
133	thread_id = pthread_self();
134
135	/* retrieve our lcore_id from the configuration structure */
136	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
137		if (thread_id == lcore_config[lcore_id].thread_id)
138			break;
139	}
140	if (lcore_id == RTE_MAX_LCORE)
141		rte_panic("cannot retrieve lcore id\n");
142
143	m2s = lcore_config[lcore_id].pipe_master2slave[0];
144	s2m = lcore_config[lcore_id].pipe_slave2master[1];
145
146	/* set the lcore ID in per-lcore memory area */
147	RTE_PER_LCORE(_lcore_id) = lcore_id;
148
149	/* set CPU affinity */
150	if (eal_thread_set_affinity() < 0)
151		rte_panic("cannot set affinity\n");
152
153	ret = eal_thread_dump_affinity(cpuset, RTE_CPU_AFFINITY_STR_LEN);
154
155	RTE_LOG(DEBUG, EAL, "lcore %u is ready (tid=%p;cpuset=[%s%s])\n",
156		lcore_id, thread_id, cpuset, ret == 0 ? "" : "...");
157
158	/* read on our pipe to get commands */
159	while (1) {
160		void *fct_arg;
161
162		/* wait command */
163		do {
164			n = read(m2s, &c, 1);
165		} while (n < 0 && errno == EINTR);
166
167		if (n <= 0)
168			rte_panic("cannot read on configuration pipe\n");
169
170		lcore_config[lcore_id].state = RUNNING;
171
172		/* send ack */
173		n = 0;
174		while (n == 0 || (n < 0 && errno == EINTR))
175			n = write(s2m, &c, 1);
176		if (n < 0)
177			rte_panic("cannot write on configuration pipe\n");
178
179		if (lcore_config[lcore_id].f == NULL)
180			rte_panic("NULL function pointer\n");
181
182		/* call the function and store the return value */
183		fct_arg = lcore_config[lcore_id].arg;
184		ret = lcore_config[lcore_id].f(fct_arg);
185		lcore_config[lcore_id].ret = ret;
186		rte_wmb();
187		lcore_config[lcore_id].state = FINISHED;
188	}
189
190	/* never reached */
191	/* pthread_exit(NULL); */
192	/* return NULL; */
193}
194
195/* require calling thread tid by gettid() */
196int rte_sys_gettid(void)
197{
198	long lwpid;
199	thr_self(&lwpid);
200	return (int)lwpid;
201}
202
203int rte_thread_setname(pthread_t id, const char *name)
204{
205	/* this BSD function returns no error */
206	pthread_set_name_np(id, name);
207	return 0;
208}
209