]> git.proxmox.com Git - mirror_frr.git/blob - lib/frr_pthread.c
Merge commit '78986c0' into tmp-3.0-master-merge
[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
23 #include "frr_pthread.h"
24 #include "memory.h"
25 #include "hash.h"
26
27 DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread");
28
29 static unsigned int next_id = 0;
30
31 /* Hash table of all frr_pthreads along with synchronization primitive(s) and
32 * hash table callbacks.
33 * ------------------------------------------------------------------------ */
34 static struct hash *pthread_table;
35 static pthread_mutex_t pthread_table_mtx = PTHREAD_MUTEX_INITIALIZER;
36
37 /* pthread_table->hash_cmp */
38 static int pthread_table_hash_cmp(const void *value1, const void *value2)
39 {
40 const struct frr_pthread *tq1 = value1;
41 const struct frr_pthread *tq2 = value2;
42
43 return (tq1->id == tq2->id);
44 }
45
46 /* pthread_table->hash_key */
47 static unsigned int pthread_table_hash_key(void *value)
48 {
49 return ((struct frr_pthread *)value)->id;
50 }
51 /* ------------------------------------------------------------------------ */
52
53 void frr_pthread_init()
54 {
55 pthread_mutex_lock(&pthread_table_mtx);
56 {
57 pthread_table = hash_create(pthread_table_hash_key,
58 pthread_table_hash_cmp, NULL);
59 }
60 pthread_mutex_unlock(&pthread_table_mtx);
61 }
62
63 void frr_pthread_finish()
64 {
65 pthread_mutex_lock(&pthread_table_mtx);
66 {
67 hash_clean(pthread_table,
68 (void (*)(void *))frr_pthread_destroy);
69 hash_free(pthread_table);
70 }
71 pthread_mutex_unlock(&pthread_table_mtx);
72 }
73
74 struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
75 void *(*start_routine)(void *),
76 int (*stop_routine)(void **,
77 struct frr_pthread *))
78 {
79 static struct frr_pthread holder = {0};
80 struct frr_pthread *fpt = NULL;
81
82 pthread_mutex_lock(&pthread_table_mtx);
83 {
84 holder.id = id;
85
86 if (!hash_lookup(pthread_table, &holder)) {
87 struct frr_pthread *fpt = XCALLOC(
88 MTYPE_FRR_PTHREAD, sizeof(struct frr_pthread));
89 fpt->id = id;
90 fpt->master = thread_master_create(name);
91 fpt->start_routine = start_routine;
92 fpt->stop_routine = stop_routine;
93 fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
94
95 hash_get(pthread_table, fpt, hash_alloc_intern);
96 }
97 }
98 pthread_mutex_unlock(&pthread_table_mtx);
99
100 return fpt;
101 }
102
103 void frr_pthread_destroy(struct frr_pthread *fpt)
104 {
105 thread_master_free(fpt->master);
106 XFREE(MTYPE_FRR_PTHREAD, fpt->name);
107 XFREE(MTYPE_FRR_PTHREAD, fpt);
108 }
109
110 struct frr_pthread *frr_pthread_get(unsigned int id)
111 {
112 static struct frr_pthread holder = {0};
113 struct frr_pthread *fpt;
114
115 pthread_mutex_lock(&pthread_table_mtx);
116 {
117 holder.id = id;
118 fpt = hash_lookup(pthread_table, &holder);
119 }
120 pthread_mutex_unlock(&pthread_table_mtx);
121
122 return fpt;
123 }
124
125 int frr_pthread_run(unsigned int id, const pthread_attr_t *attr, void *arg)
126 {
127 struct frr_pthread *fpt = frr_pthread_get(id);
128 int ret;
129
130 if (!fpt)
131 return -1;
132
133 ret = pthread_create(&fpt->thread, attr, fpt->start_routine, arg);
134
135 /* Per pthread_create(3), the contents of fpt->thread are undefined if
136 * pthread_create() did not succeed. Reset this value to zero. */
137 if (ret < 0)
138 memset(&fpt->thread, 0x00, sizeof(fpt->thread));
139
140 return ret;
141 }
142
143 /**
144 * Calls the stop routine for the frr_pthread and resets any relevant fields.
145 *
146 * @param fpt - the frr_pthread to stop
147 * @param result - pointer to result pointer
148 * @return the return code from the stop routine
149 */
150 static int frr_pthread_stop_actual(struct frr_pthread *fpt, void **result)
151 {
152 int ret = (*fpt->stop_routine)(result, fpt);
153 memset(&fpt->thread, 0x00, sizeof(fpt->thread));
154 return ret;
155 }
156
157 int frr_pthread_stop(unsigned int id, void **result)
158 {
159 struct frr_pthread *fpt = frr_pthread_get(id);
160 return frr_pthread_stop_actual(fpt, result);
161 }
162
163 /**
164 * Callback for hash_iterate to stop all frr_pthread's.
165 */
166 static void frr_pthread_stop_all_iter(struct hash_backet *hb, void *arg)
167 {
168 struct frr_pthread *fpt = hb->data;
169 frr_pthread_stop_actual(fpt, NULL);
170 }
171
172 void frr_pthread_stop_all()
173 {
174 pthread_mutex_lock(&pthread_table_mtx);
175 {
176 hash_iterate(pthread_table, frr_pthread_stop_all_iter, NULL);
177 }
178 pthread_mutex_unlock(&pthread_table_mtx);
179 }
180
181 unsigned int frr_pthread_get_id()
182 {
183 return next_id++;
184 }