* Reimplementation of the code that allows the .pinerc file to be a
[alpine.git] / alpine / after.c
bloba8b1ce7014ae2a57bf04e5af6f98a14f964111e4
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: after.c 138 2006-09-22 22:12:03Z mikes@u.washington.edu $";
3 #endif
5 /* ========================================================================
6 * Copyright 2006-2007 University of Washington
7 * Copyright 2013-2015 Eduardo Chappa
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * ========================================================================
18 /*======================================================================
19 Implement asynchronous start_after() call
20 ====*/
23 #include <system.h>
24 #include <general.h>
26 #include "../pith/debug.h"
27 #include "../pith/osdep/err_desc.h"
29 #include "../pico/utf8stub.h"
31 #include "after.h"
34 /* internal state */
35 int after_active;
37 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
38 static pthread_t after_thread;
39 static pthread_mutex_t status_message_mutex;
40 #endif
43 /* internal prototypes */
44 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
45 void *do_after(void *);
46 #else
47 void *cleanup_data;
48 #endif
50 void cleanup_after(void *);
54 * start_after - pause and/or loop calling passed function
55 * without getting in the way of main thread
58 void
59 start_after(AFTER_S *a)
61 if(a){
62 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
63 pthread_attr_t attr;
64 int rc;
65 size_t stack;
67 if(after_active)
68 stop_after(1);
70 /* Initialize and set thread detached attribute */
71 pthread_attr_init(&attr);
72 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
73 #if defined(PTHREAD_STACK_MIN)
74 stack = PTHREAD_STACK_MIN + 0x10000;
75 pthread_attr_setstacksize(&attr, stack);
76 #endif
78 if((rc = pthread_create(&after_thread, &attr, do_after, (void *) a)) != 0){
79 after_active = 0;
80 dprint((1, "start_after: pthread_create failed %d (%d)", rc, errno));
82 else
83 after_active = 1;
85 pthread_attr_destroy(&attr);
86 dprint((9, "start_after() created %x: done", after_thread));
87 #else /* !(defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)) */
89 * Just call the first function
91 if(!a->delay)
92 (void) (*a->f)(a->data); /* do the thing */
94 cleanup_data = (void *) a;
95 after_active = 1;
96 #endif
102 * stop_after - stop the thread
104 void
105 stop_after(int join)
107 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
108 int rv;
110 dprint((9, "stop_after(join=%d) tid=%x", join, pthread_self()));
112 if(after_active){
113 if((rv = pthread_cancel(after_thread)) != 0){ /* tell thread to end */
114 dprint((1, "pthread_cancel: %d (%s)\n", rv, error_description(errno)));
117 if(join){
118 if((rv = pthread_join(after_thread, NULL)) != 0){ /* wait for it to end */
119 dprint((1, "pthread_join: %d (%s)\n", rv, error_description(errno)));
122 else if((rv = pthread_detach(after_thread)) != 0){ /* mark thread for deletion */
123 dprint((1, "pthread_detach: %d (%s)\n", rv, error_description(errno)));
127 /* not literally true uless "join" set */
128 after_active = 0;
130 #else /* !(defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)) */
132 cleanup_after((void *) cleanup_data);
133 cleanup_data = NULL;
134 after_active = 0;
136 #endif
140 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
142 * do_after - loop thru list of pause/loop functions
144 void *
145 do_after(void *data)
147 AFTER_S *a;
148 struct timespec ts;
149 int loop;
150 sigset_t sigs;
152 #if defined(SIGCHLD) || defined(SIGWINCH)
153 sigemptyset(&sigs);
154 #if defined(SIGCHLD)
155 /* make sure we don't end up with SIGCHLD */
156 sigaddset(&sigs, SIGCHLD);
157 #endif /* SIGCHLD */
158 #if defined(SIGCHLD)
159 /* or with SIGWINCH */
160 sigaddset(&sigs, SIGWINCH);
161 #endif /* SIGWINCH */
162 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
163 #endif
165 /* prepare for the finish */
166 pthread_cleanup_push(cleanup_after, data);
167 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
168 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
170 /* and jump in */
171 for(a = (AFTER_S *) data; a != NULL && a->f != NULL; a = a->next){
172 if(a->delay){
173 ts.tv_sec = a->delay / 100; /* seconds */
174 ts.tv_nsec = (a->delay % 100) * 10000000;
176 if(nanosleep(&ts, NULL))
177 pthread_exit(NULL); /* interrupted */
180 while(1){
181 /* after waking, make sure we're still wanted */
182 pthread_testcancel();
184 loop = (*a->f)(a->data); /* do the thing */
186 if(loop > 0){
187 ts.tv_sec = loop / 100;
188 ts.tv_nsec = (loop % 100) * 10000000;
190 if(nanosleep(&ts, NULL))
191 pthread_exit(NULL); /* interrupted */
193 else
194 break;
198 pthread_cleanup_pop(1);
199 pthread_exit(NULL);
202 #endif /* defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP) */
206 * cleanup_after - give start_after caller opportunity to clean up
207 * their data, then free up AFTER_S list
209 void
210 cleanup_after(void *data)
212 AFTER_S *a, *an;
214 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
215 dprint((9, "cleanup_after() tid=%x", pthread_self()));
216 #endif
218 /* free linked list of AFTER_S's */
219 a = (AFTER_S *) data;
220 while(a != NULL){
221 an = a->next;
223 if(a->cf)
224 (*a->cf)(a->data);
226 free((void *) a);
228 a = an;
233 AFTER_S *
234 new_afterstruct(void)
236 AFTER_S *a;
238 if((a = (AFTER_S *)malloc(sizeof(AFTER_S))) == NULL){
239 fatal("Out of memory");
242 memset((void *) a, 0, sizeof(AFTER_S));
244 return(a);
248 void
249 status_message_lock_init(void)
251 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
252 pthread_mutex_init(&status_message_mutex, NULL);
253 #endif
258 status_message_lock(void)
260 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
261 return(pthread_mutex_lock(&status_message_mutex));
262 #else
263 return(0);
264 #endif
269 status_message_unlock(void)
271 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
272 return(pthread_mutex_unlock(&status_message_mutex));
273 #else
274 return(0);
275 #endif