1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: after.c 138 2006-09-22 22:12:03Z mikes@u.washington.edu $";
5 /* ========================================================================
6 * Copyright 2013-2020 Eduardo Chappa
7 * Copyright 2006-2007 University of Washington
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
26 #include "../pith/debug.h"
27 #include "../pith/osdep/err_desc.h"
29 #include "../pico/utf8stub.h"
37 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
38 static pthread_t after_thread
;
39 static pthread_mutex_t status_message_mutex
;
43 /* internal prototypes */
44 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
45 void *do_after(void *);
50 void cleanup_after(void *);
54 * start_after - pause and/or loop calling passed function
55 * without getting in the way of main thread
59 start_after(AFTER_S
*a
)
62 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
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
);
78 if((rc
= pthread_create(&after_thread
, &attr
, do_after
, (void *) a
)) != 0){
80 dprint((1, "start_after: pthread_create failed %d (%d)", rc
, errno
));
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
92 (void) (*a
->f
)(a
->data
); /* do the thing */
94 cleanup_data
= (void *) a
;
102 * stop_after - stop the thread
107 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
110 dprint((9, "stop_after(join=%d) tid=%x", join
, pthread_self()));
113 if((rv
= pthread_cancel(after_thread
)) != 0){ /* tell thread to end */
114 dprint((1, "pthread_cancel: %d (%s)\n", rv
, error_description(errno
)));
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 */
130 #else /* !(defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)) */
132 cleanup_after((void *) cleanup_data
);
140 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
142 * do_after - loop thru list of pause/loop functions
152 #if defined(SIGCHLD) || defined(SIGWINCH)
155 /* make sure we don't end up with SIGCHLD */
156 sigaddset(&sigs
, SIGCHLD
);
159 /* or with SIGWINCH */
160 sigaddset(&sigs
, SIGWINCH
);
161 #endif /* SIGWINCH */
162 pthread_sigmask(SIG_BLOCK
, &sigs
, NULL
);
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
);
171 for(a
= (AFTER_S
*) data
; a
!= NULL
&& a
->f
!= NULL
; a
= a
->next
){
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 */
181 /* after waking, make sure we're still wanted */
182 pthread_testcancel();
184 loop
= (*a
->f
)(a
->data
); /* do the thing */
187 ts
.tv_sec
= loop
/ 100;
188 ts
.tv_nsec
= (loop
% 100) * 10000000;
190 if(nanosleep(&ts
, NULL
))
191 pthread_exit(NULL
); /* interrupted */
198 pthread_cleanup_pop(1);
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
210 cleanup_after(void *data
)
214 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
215 dprint((9, "cleanup_after() tid=%x", pthread_self()));
218 /* free linked list of AFTER_S's */
219 a
= (AFTER_S
*) data
;
234 new_afterstruct(void)
238 if((a
= (AFTER_S
*)malloc(sizeof(AFTER_S
))) == NULL
){
239 fatal("Out of memory");
242 memset((void *) a
, 0, sizeof(AFTER_S
));
249 status_message_lock_init(void)
251 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
252 pthread_mutex_init(&status_message_mutex
, NULL
);
258 status_message_lock(void)
260 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
261 return(pthread_mutex_lock(&status_message_mutex
));
269 status_message_unlock(void)
271 #if defined(HAVE_PTHREAD) && defined(HAVE_NANOSLEEP)
272 return(pthread_mutex_unlock(&status_message_mutex
));