]> git.proxmox.com Git - mirror_frr.git/blob - lib/frr_pthread.c
Merge pull request #1634 from qlyoung/vtysh-output-file
[mirror_frr.git] / lib / frr_pthread.c
1 /*
2 * Utilities and interfaces for managing POSIX threads
3 * Copyright (C) 2017 Cumulus Networks
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <zebra.h>
21 #include <pthread.h>
22 #include <sched.h>
23
24 #include "frr_pthread.h"
25 #include "memory.h"
26 #include "hash.h"
27
28 DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread");
29 DEFINE_MTYPE(LIB, PTHREAD_PRIM, "POSIX synchronization primitives");
30
31 static unsigned int next_id = 0;
32
33 /* Hash table of all frr_pthreads along with synchronization primitive(s) and
34 * hash table callbacks.
35 * ------------------------------------------------------------------------ */
36 static struct hash *pthread_table;
37 static pthread_mutex_t pthread_table_mtx = PTHREAD_MUTEX_INITIALIZER;
38
39 /* pthread_table->hash_cmp */
40 static int pthread_table_hash_cmp(const void *value1, const void *value2)
41 {
42 const struct frr_pthread *tq1 = value1;
43 const struct frr_pthread *tq2 = value2;
44
45 return (tq1->id == tq2->id);
46 }
47
48 /* pthread_table->hash_key */
49 static unsigned int pthread_table_hash_key(void *value)
50 {
51 return ((struct frr_pthread *)value)->id;
52 }
53 /* ------------------------------------------------------------------------ */
54
55 void frr_pthread_init()
56 {
57 pthread_mutex_lock(&pthread_table_mtx);
58 {
59 pthread_table = hash_create(pthread_table_hash_key,
60 pthread_table_hash_cmp, NULL);
61 }
62 pthread_mutex_unlock(&pthread_table_mtx);
63 }
64
65 void frr_pthread_finish()
66 {
67 pthread_mutex_lock(&pthread_table_mtx);
68 {
69 hash_clean(pthread_table,
70 (void (*)(void *))frr_pthread_destroy);
71 hash_free(pthread_table);
72 }
73 pthread_mutex_unlock(&pthread_table_mtx);
74 }
75
76 struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
77 void *(*start_routine)(void *),
78 int (*stop_routine)(void **,
79 struct frr_pthread *))
80 {
81 static struct frr_pthread holder = {0};
82 struct frr_pthread *fpt = NULL;
83
84 pthread_mutex_lock(&pthread_table_mtx);
85 {
86 holder.id = id;
87
88 if (!hash_lookup(pthread_table, &holder)) {
89 struct frr_pthread *fpt = XCALLOC(
90 MTYPE_FRR_PTHREAD, sizeof(struct frr_pthread));
91 fpt->id = id;
92 fpt->master = thread_master_create(name);
93 fpt->start_routine = start_routine;
94 fpt->stop_routine = stop_routine;
95 fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
96
97 hash_get(pthread_table, fpt, hash_alloc_intern);
98 }
99 }
100 pthread_mutex_unlock(&pthread_table_mtx);
101
102 return fpt;
103 }
104
105 void frr_pthread_destroy(struct frr_pthread *fpt)
106 {
107 thread_master_free(fpt->master);
108 XFREE(MTYPE_FRR_PTHREAD, fpt->name);
109 XFREE(MTYPE_FRR_PTHREAD, fpt);
110 }
111
112 struct frr_pthread *frr_pthread_get(unsigned int id)
113 {
114 static struct frr_pthread holder = {0};
115 struct frr_pthread *fpt;
116
117 pthread_mutex_lock(&pthread_table_mtx);
118 {
119 holder.id = id;
120 fpt = hash_lookup(pthread_table, &holder);
121 }
122 pthread_mutex_unlock(&pthread_table_mtx);
123
124 return fpt;
125 }
126
127 int frr_pthread_run(unsigned int id, const pthread_attr_t *attr, void *arg)
128 {
129 struct frr_pthread *fpt = frr_pthread_get(id);
130 int ret;
131
132 if (!fpt)
133 return -1;
134
135 ret = pthread_create(&fpt->thread, attr, fpt->start_routine, arg);
136
137 /* Per pthread_create(3), the contents of fpt->thread are undefined if
138 * pthread_create() did not succeed. Reset this value to zero. */
139 if (ret < 0)
140 memset(&fpt->thread, 0x00, sizeof(fpt->thread));
141
142 return ret;
143 }
144
145 /**
146 * Calls the stop routine for the frr_pthread and resets any relevant fields.
147 *
148 * @param fpt - the frr_pthread to stop
149 * @param result - pointer to result pointer
150 * @return the return code from the stop routine
151 */
152 static int frr_pthread_stop_actual(struct frr_pthread *fpt, void **result)
153 {
154 int ret = (*fpt->stop_routine)(result, fpt);
155 memset(&fpt->thread, 0x00, sizeof(fpt->thread));
156 return ret;
157 }
158
159 int frr_pthread_stop(unsigned int id, void **result)
160 {
161 struct frr_pthread *fpt = frr_pthread_get(id);
162 return frr_pthread_stop_actual(fpt, result);
163 }
164
165 /**
166 * Callback for hash_iterate to stop all frr_pthread's.
167 */
168 static void frr_pthread_stop_all_iter(struct hash_backet *hb, void *arg)
169 {
170 struct frr_pthread *fpt = hb->data;
171 frr_pthread_stop_actual(fpt, NULL);
172 }
173
174 void frr_pthread_stop_all()
175 {
176 pthread_mutex_lock(&pthread_table_mtx);
177 {
178 hash_iterate(pthread_table, frr_pthread_stop_all_iter, NULL);
179 }
180 pthread_mutex_unlock(&pthread_table_mtx);
181 }
182
183 unsigned int frr_pthread_get_id()
184 {
185 return next_id++;
186 }
187
188 void frr_pthread_yield(void)
189 {
190 (void)sched_yield();
191 }