1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2003-2021 The OpenLDAP Foundation.
5  * Portions Copyright 2003 IBM Corporation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* This work was initially developed by Jong Hyuk Choi for inclusion
17  * in OpenLDAP Software.
18  */
19 
20 #include "portable.h"
21 
22 #include <stdio.h>
23 
24 #include <ac/stdarg.h>
25 #include <ac/stdlib.h>
26 #include <ac/errno.h>
27 #include <ac/socket.h>
28 #include <ac/string.h>
29 #include <ac/time.h>
30 
31 #include "ldap-int.h"
32 
33 #ifdef LDAP_R_COMPILE
34 
35 #include "ldap_pvt_thread.h"
36 #include "ldap_queue.h"
37 #include "ldap_rq.h"
38 
39 struct re_s *
ldap_pvt_runqueue_insert(struct runqueue_s * rq,time_t interval,ldap_pvt_thread_start_t * routine,void * arg,char * tname,char * tspec)40 ldap_pvt_runqueue_insert(
41 	struct runqueue_s* rq,
42 	time_t interval,
43 	ldap_pvt_thread_start_t *routine,
44 	void *arg,
45 	char *tname,
46 	char *tspec
47 )
48 {
49 	struct re_s* entry;
50 
51 	entry = (struct re_s *) LDAP_CALLOC( 1, sizeof( struct re_s ));
52 	if ( entry ) {
53 		entry->interval.tv_sec = interval;
54 		entry->interval.tv_usec = 0;
55 		entry->next_sched.tv_sec = time( NULL );
56 		entry->next_sched.tv_usec = 0;
57 		entry->routine = routine;
58 		entry->arg = arg;
59 		entry->tname = tname;
60 		entry->tspec = tspec;
61 		LDAP_STAILQ_INSERT_HEAD( &rq->task_list, entry, tnext );
62 	}
63 	return entry;
64 }
65 
66 struct re_s *
ldap_pvt_runqueue_find(struct runqueue_s * rq,ldap_pvt_thread_start_t * routine,void * arg)67 ldap_pvt_runqueue_find(
68 	struct runqueue_s *rq,
69 	ldap_pvt_thread_start_t *routine,
70 	void *arg
71 )
72 {
73 	struct re_s* e;
74 
75 	LDAP_STAILQ_FOREACH( e, &rq->task_list, tnext ) {
76 		if ( e->routine == routine && e->arg == arg )
77 			return e;
78 	}
79 	return NULL;
80 }
81 
82 void
ldap_pvt_runqueue_remove(struct runqueue_s * rq,struct re_s * entry)83 ldap_pvt_runqueue_remove(
84 	struct runqueue_s* rq,
85 	struct re_s* entry
86 )
87 {
88 	struct re_s* e;
89 
90 	LDAP_STAILQ_FOREACH( e, &rq->task_list, tnext ) {
91 		if ( e == entry)
92 			break;
93 	}
94 
95 	assert( e == entry );
96 
97 	LDAP_STAILQ_REMOVE( &rq->task_list, entry, re_s, tnext );
98 
99 	LDAP_FREE( entry );
100 }
101 
102 struct re_s*
ldap_pvt_runqueue_next_sched(struct runqueue_s * rq,struct timeval * next_run)103 ldap_pvt_runqueue_next_sched(
104 	struct runqueue_s* rq,
105 	struct timeval* next_run
106 )
107 {
108 	struct re_s* entry;
109 
110 	entry = LDAP_STAILQ_FIRST( &rq->task_list );
111 	if ( entry == NULL || entry->next_sched.tv_sec == 0 ) {
112 		return NULL;
113 	} else {
114 		*next_run = entry->next_sched;
115 		return entry;
116 	}
117 }
118 
119 void
ldap_pvt_runqueue_runtask(struct runqueue_s * rq,struct re_s * entry)120 ldap_pvt_runqueue_runtask(
121 	struct runqueue_s* rq,
122 	struct re_s* entry
123 )
124 {
125 	LDAP_STAILQ_INSERT_TAIL( &rq->run_list, entry, rnext );
126 }
127 
128 void
ldap_pvt_runqueue_stoptask(struct runqueue_s * rq,struct re_s * entry)129 ldap_pvt_runqueue_stoptask(
130 	struct runqueue_s* rq,
131 	struct re_s* entry
132 )
133 {
134 	LDAP_STAILQ_REMOVE( &rq->run_list, entry, re_s, rnext );
135 }
136 
137 int
ldap_pvt_runqueue_isrunning(struct runqueue_s * rq,struct re_s * entry)138 ldap_pvt_runqueue_isrunning(
139 	struct runqueue_s* rq,
140 	struct re_s* entry
141 )
142 {
143 	struct re_s* e;
144 
145 	LDAP_STAILQ_FOREACH( e, &rq->run_list, rnext ) {
146 		if ( e == entry ) {
147 			return 1;
148 		}
149 	}
150 	return 0;
151 }
152 
153 void
ldap_pvt_runqueue_resched(struct runqueue_s * rq,struct re_s * entry,int defer)154 ldap_pvt_runqueue_resched(
155 	struct runqueue_s* rq,
156 	struct re_s* entry,
157 	int defer
158 )
159 {
160 	struct re_s* prev;
161 	struct re_s* e;
162 
163 	LDAP_STAILQ_FOREACH( e, &rq->task_list, tnext ) {
164 		if ( e == entry )
165 			break;
166 	}
167 
168 	assert ( e == entry );
169 
170 	LDAP_STAILQ_REMOVE( &rq->task_list, entry, re_s, tnext );
171 
172 	if ( !defer ) {
173 		entry->next_sched.tv_sec = time( NULL ) + entry->interval.tv_sec;
174 	} else {
175 		entry->next_sched.tv_sec = 0;
176 	}
177 
178 	if ( LDAP_STAILQ_EMPTY( &rq->task_list )) {
179 		LDAP_STAILQ_INSERT_HEAD( &rq->task_list, entry, tnext );
180 	} else if ( entry->next_sched.tv_sec == 0 ) {
181 		LDAP_STAILQ_INSERT_TAIL( &rq->task_list, entry, tnext );
182 	} else {
183 		prev = NULL;
184 		LDAP_STAILQ_FOREACH( e, &rq->task_list, tnext ) {
185 			if ( e->next_sched.tv_sec == 0 ) {
186 				if ( prev == NULL ) {
187 					LDAP_STAILQ_INSERT_HEAD( &rq->task_list, entry, tnext );
188 				} else {
189 					LDAP_STAILQ_INSERT_AFTER( &rq->task_list, prev, entry, tnext );
190 				}
191 				return;
192 			} else if ( e->next_sched.tv_sec > entry->next_sched.tv_sec ) {
193 				if ( prev == NULL ) {
194 					LDAP_STAILQ_INSERT_HEAD( &rq->task_list, entry, tnext );
195 				} else {
196 					LDAP_STAILQ_INSERT_AFTER( &rq->task_list, prev, entry, tnext );
197 				}
198 				return;
199 			}
200 			prev = e;
201 		}
202 		LDAP_STAILQ_INSERT_TAIL( &rq->task_list, entry, tnext );
203 	}
204 }
205 
206 int
ldap_pvt_runqueue_persistent_backload(struct runqueue_s * rq)207 ldap_pvt_runqueue_persistent_backload(
208 	struct runqueue_s* rq
209 )
210 {
211 	struct re_s* e;
212 	int count = 0;
213 
214 	ldap_pvt_thread_mutex_lock( &rq->rq_mutex );
215 	if ( !LDAP_STAILQ_EMPTY( &rq->task_list )) {
216 		LDAP_STAILQ_FOREACH( e, &rq->task_list, tnext ) {
217 			if ( e->next_sched.tv_sec == 0 )
218 				count++;
219 		}
220 	}
221 	ldap_pvt_thread_mutex_unlock( &rq->rq_mutex );
222 	return count;
223 }
224 
225 #endif /* LDAP_R_COMPILE */
226