]>
Commit | Line | Data |
---|---|---|
98f14af8 QY |
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 | |
16 | along with this program; see the file COPYING; if not, write to the | |
17 | Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, | |
18 | MA 02110-1301 USA | |
19 | */ | |
20 | ||
21 | #include <zebra.h> | |
22 | #include <pthread.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 | ||
30 | static unsigned int next_id = 0; | |
31 | ||
32 | /* Hash table of all frr_pthreads along with synchronization primitive(s) and | |
33 | * hash table callbacks. | |
34 | * ------------------------------------------------------------------------ */ | |
35 | static struct hash *pthread_table; | |
36 | static pthread_mutex_t pthread_table_mtx = PTHREAD_MUTEX_INITIALIZER; | |
37 | ||
38 | /* pthread_table->hash_cmp */ | |
39 | static int pthread_table_hash_cmp(const void *value1, const void *value2) | |
40 | { | |
41 | const struct frr_pthread *tq1 = value1; | |
42 | const struct frr_pthread *tq2 = value2; | |
43 | ||
44 | return (tq1->id == tq2->id); | |
45 | } | |
46 | ||
47 | /* pthread_table->hash_key */ | |
48 | static unsigned int pthread_table_hash_key(void *value) | |
49 | { | |
50 | return ((struct frr_pthread *)value)->id; | |
51 | } | |
52 | /* ------------------------------------------------------------------------ */ | |
53 | ||
54 | void frr_pthread_init() | |
55 | { | |
56 | pthread_mutex_lock(&pthread_table_mtx); | |
57 | { | |
58 | pthread_table = | |
59 | hash_create(pthread_table_hash_key, pthread_table_hash_cmp); | |
60 | } | |
61 | pthread_mutex_unlock(&pthread_table_mtx); | |
62 | } | |
63 | ||
64 | void frr_pthread_finish() | |
65 | { | |
66 | pthread_mutex_lock(&pthread_table_mtx); | |
67 | { | |
68 | hash_clean(pthread_table, (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 **, struct frr_pthread *)) | |
77 | { | |
78 | static struct frr_pthread holder = { 0 }; | |
79 | struct frr_pthread *fpt = NULL; | |
80 | ||
81 | pthread_mutex_lock(&pthread_table_mtx); | |
82 | { | |
83 | holder.id = id; | |
84 | ||
85 | if (!hash_lookup(pthread_table, &holder)) { | |
86 | struct frr_pthread *fpt = | |
87 | XCALLOC(MTYPE_FRR_PTHREAD, | |
88 | sizeof(struct frr_pthread)); | |
89 | fpt->id = id; | |
90 | fpt->master = thread_master_create(); | |
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 | } |