]> git.proxmox.com Git - mirror_frr.git/blame - lib/frr_pthread.c
lib: add pthread manager
[mirror_frr.git] / lib / frr_pthread.c
CommitLineData
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
28DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread");
29
30static unsigned int next_id = 0;
31
32/* Hash table of all frr_pthreads along with synchronization primitive(s) and
33 * hash table callbacks.
34 * ------------------------------------------------------------------------ */
35static struct hash *pthread_table;
36static pthread_mutex_t pthread_table_mtx = PTHREAD_MUTEX_INITIALIZER;
37
38/* pthread_table->hash_cmp */
39static 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 */
48static unsigned int pthread_table_hash_key(void *value)
49{
50 return ((struct frr_pthread *)value)->id;
51}
52/* ------------------------------------------------------------------------ */
53
54void 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
64void 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
74struct 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
103void 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
110struct 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
125int 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 */
150static 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
157int 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 */
166static 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
172void 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
181unsigned int frr_pthread_get_id()
182{
183 return next_id++;
184}