2 * Utilities and interfaces for managing POSIX threads
3 * Copyright (C) 2017 Cumulus Networks
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.
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.
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
23 #include "frr_pthread.h"
27 DEFINE_MTYPE_STATIC(LIB
, FRR_PTHREAD
, "FRR POSIX Thread");
29 static unsigned int next_id
= 0;
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
;
37 /* pthread_table->hash_cmp */
38 static int pthread_table_hash_cmp(const void *value1
, const void *value2
)
40 const struct frr_pthread
*tq1
= value1
;
41 const struct frr_pthread
*tq2
= value2
;
43 return (tq1
->id
== tq2
->id
);
46 /* pthread_table->hash_key */
47 static unsigned int pthread_table_hash_key(void *value
)
49 return ((struct frr_pthread
*)value
)->id
;
51 /* ------------------------------------------------------------------------ */
53 void frr_pthread_init()
55 pthread_mutex_lock(&pthread_table_mtx
);
57 pthread_table
= hash_create(pthread_table_hash_key
,
58 pthread_table_hash_cmp
, NULL
);
60 pthread_mutex_unlock(&pthread_table_mtx
);
63 void frr_pthread_finish()
65 pthread_mutex_lock(&pthread_table_mtx
);
67 hash_clean(pthread_table
,
68 (void (*)(void *))frr_pthread_destroy
);
69 hash_free(pthread_table
);
71 pthread_mutex_unlock(&pthread_table_mtx
);
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
*))
79 static struct frr_pthread holder
= {0};
80 struct frr_pthread
*fpt
= NULL
;
82 pthread_mutex_lock(&pthread_table_mtx
);
86 if (!hash_lookup(pthread_table
, &holder
)) {
87 struct frr_pthread
*fpt
= XCALLOC(
88 MTYPE_FRR_PTHREAD
, sizeof(struct frr_pthread
));
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
);
95 hash_get(pthread_table
, fpt
, hash_alloc_intern
);
98 pthread_mutex_unlock(&pthread_table_mtx
);
103 void frr_pthread_destroy(struct frr_pthread
*fpt
)
105 thread_master_free(fpt
->master
);
106 XFREE(MTYPE_FRR_PTHREAD
, fpt
->name
);
107 XFREE(MTYPE_FRR_PTHREAD
, fpt
);
110 struct frr_pthread
*frr_pthread_get(unsigned int id
)
112 static struct frr_pthread holder
= {0};
113 struct frr_pthread
*fpt
;
115 pthread_mutex_lock(&pthread_table_mtx
);
118 fpt
= hash_lookup(pthread_table
, &holder
);
120 pthread_mutex_unlock(&pthread_table_mtx
);
125 int frr_pthread_run(unsigned int id
, const pthread_attr_t
*attr
, void *arg
)
127 struct frr_pthread
*fpt
= frr_pthread_get(id
);
133 ret
= pthread_create(&fpt
->thread
, attr
, fpt
->start_routine
, arg
);
135 /* Per pthread_create(3), the contents of fpt->thread are undefined if
136 * pthread_create() did not succeed. Reset this value to zero. */
138 memset(&fpt
->thread
, 0x00, sizeof(fpt
->thread
));
144 * Calls the stop routine for the frr_pthread and resets any relevant fields.
146 * @param fpt - the frr_pthread to stop
147 * @param result - pointer to result pointer
148 * @return the return code from the stop routine
150 static int frr_pthread_stop_actual(struct frr_pthread
*fpt
, void **result
)
152 int ret
= (*fpt
->stop_routine
)(result
, fpt
);
153 memset(&fpt
->thread
, 0x00, sizeof(fpt
->thread
));
157 int frr_pthread_stop(unsigned int id
, void **result
)
159 struct frr_pthread
*fpt
= frr_pthread_get(id
);
160 return frr_pthread_stop_actual(fpt
, result
);
164 * Callback for hash_iterate to stop all frr_pthread's.
166 static void frr_pthread_stop_all_iter(struct hash_backet
*hb
, void *arg
)
168 struct frr_pthread
*fpt
= hb
->data
;
169 frr_pthread_stop_actual(fpt
, NULL
);
172 void frr_pthread_stop_all()
174 pthread_mutex_lock(&pthread_table_mtx
);
176 hash_iterate(pthread_table
, frr_pthread_stop_all_iter
, NULL
);
178 pthread_mutex_unlock(&pthread_table_mtx
);
181 unsigned int frr_pthread_get_id()