Hi Gilles, Gilles Chanteperdrix wrote: > Gilles Chanteperdrix wrote: >>>> Now, the question is, do you realistically plan to write an application >>>> which makes no syscall in its real-time loop? >>> Unlikely, but it may happen in case of programming errors. Anyhow, the >>> pthreads will run legacy code and it would be a pain to add >>> pthread_testcancel where necessary. But maybe there is a more elegant >>> and simple solution to do a defined exit/abort. >> In case of programming error, enable the xenomai watchdog, it will >> forcibly kill the problematic thread. > > To give you a more complete answer: most blocking functions are > cancellation points in the PTHREAD_CANCEL_DEFERRED case, so, you > probably do not need to add pthread_testcancel at all. The only > exception is pthread_mutex_lock: this way, cancellation happens for well > defined mutex states, and you may install cleanup handlers with > pthread_cleanup_push/pthread_cleanup_pop if ever a thread may be > destroyed while holding a mutex. With PTHREAD_CANCEL_ASYNCHRONOUS, the > situation is not that clean.
Well, there seems something wrong with it, also PTHREAD_CANCEL_DEFERRED with pthread_testcancel does not work reliably and consistently and it still behaves different on my ARM and PowerPC systems. I have attached my revised test program allowing to enable/disable various method of thread creation, setup and cancellation. They all work fine with the Linux POSIX libraries. With Xenomai, only a few work as expected on my ARM and PowerPC test systems. It would be nice if somebody could test it on a X86 system. Maybe there is still something wrong with my test program. I'm also puzzled why pthread_setschedparam() does make a mode switch to secondary mode (sometimes). Wolfgang.
/* * Test program for thread cancelation */ #include <execinfo.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <time.h> #include <sys/mman.h> #ifndef __XENO__ #define rt_printf printf #else #include <rtdk.h> #endif //#define USE_SIGXCPU //#define USE_EXPLICIT_SCHED #define CANCEL_TYPE PTHREAD_CANCEL_DEFERRED //#define CANCEL_TYPE PTHREAD_CANCEL_ASYNCHRONOUS #define USE_TEST_CANCEL #define CTRL_PRIO 39 #define CALC_PRIO 38 static pthread_t calc_thread; static pthread_t ctrl_thread; volatile unsigned long count = 0; static int load_ms = 2500; static int calc_exit; void check_err(char *string, int err) { if (err) { printf("Failed with %d at %s", err, string); exit(1); } } static void create_load_100ms(void) { struct timespec now, stop; clock_gettime(CLOCK_MONOTONIC, &stop); stop.tv_nsec += 100000000; if (stop.tv_nsec >= 1000000000) { stop.tv_nsec -= 1000000000; stop.tv_sec++; } while (1) { #ifdef USE_TEST_CANCEL pthread_testcancel(); #endif clock_gettime(CLOCK_MONOTONIC, &now); if (now.tv_sec > stop.tv_sec) break; else if (now.tv_sec == stop.tv_sec && now.tv_nsec >= stop.tv_nsec) break; } } void *ctrl_func(void *parm) { struct timespec ts; #ifndef USE_EXPLICIT_SCHED struct sched_param param; #endif int rc; #ifdef __XENO__ pthread_set_name_np(pthread_self(), __func__); #ifdef USE_SIGXCPU pthread_set_mode_np(0, PTHREAD_WARNSW); #endif #endif #ifndef USE_EXPLICIT_SCHED memset(¶m, 0 , sizeof(param)); param.sched_priority = CTRL_PRIO; rc = pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m); check_err("pthread_setschedparam()\n", rc); #endif rt_printf("%s: started at count %ld\n", __func__, count); ts.tv_sec = load_ms / 1000; ts.tv_nsec = (load_ms % 1000) * 1000000; rt_printf("%s: sleeping for %ldsec %ldns\n", __func__, (long)ts.tv_sec, (long)ts.tv_nsec); nanosleep(&ts, NULL); if (!calc_exit) { rt_printf("%s: cancel at count %ld\n", __func__, count); pthread_cancel(calc_thread); } rt_printf("%s: stopped at count %ld\n", __func__, count); return NULL; } void *calc_func(void *parm) { int rc , count_max; #ifndef USE_EXPLICIT_SCHED struct sched_param param; memset(¶m, 0 , sizeof(param)); param.sched_priority = CALC_PRIO; rc = pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m); check_err("pthread_setschedparam()\n", rc); #endif #ifdef __XENO__ pthread_set_name_np(pthread_self(), __func__); #ifdef USE_SIGXCPU pthread_set_mode_np(0, PTHREAD_WARNSW); #endif #endif #ifdef CANCEL_TYPE rc = pthread_setcanceltype(CANCEL_TYPE, NULL); check_err("pthread_setcanceltype()\n", rc); #endif count_max = 2 * load_ms / 100; rt_printf("%s: counting till %d\n", __func__, count_max); while (count < count_max) { create_load_100ms(); rt_printf("%s: at count %ld\n", __func__, count); count++; } rt_printf("%s: stopped at count %ld\n", __func__, count); calc_exit = 1; return NULL; } #ifdef USE_SIGXCPU void mode_switch_handler(int sig) { void *bt[32]; int nentries; /* Dump a backtrace of the frame which caused the switch to secondary mode: */ nentries = backtrace(bt,sizeof(bt) / sizeof(bt[0])); backtrace_symbols_fd(bt, nentries, fileno(stdout)); } #endif int main(int argc, char **argv) { int rc = 0; void *status; #ifdef USE_EXPLICIT_SCHED pthread_attr_t calc_attr, ctrl_attr; struct sched_param calc_param, ctrl_param; #endif if (argc == 2) load_ms = atoi(argv[1]); /* Lock process memory */ mlockall(MCL_CURRENT | MCL_FUTURE); #ifdef USE_SIGXCPU signal(SIGXCPU, mode_switch_handler); #endif #ifdef __XENO__ /* We use rt_printf() for debugging real-time code */ rt_print_auto_init(1); rt_printf("Real-Time debugging started\n"); #endif #ifdef USE_EXPLICIT_SCHED memset(&ctrl_param, 0 , sizeof(ctrl_param)); pthread_attr_init(&ctrl_attr); pthread_attr_setschedpolicy(&ctrl_attr, SCHED_FIFO); ctrl_param.sched_priority = CTRL_PRIO; pthread_attr_setschedparam(&ctrl_attr, &ctrl_param); pthread_attr_setinheritsched(&ctrl_attr, PTHREAD_EXPLICIT_SCHED); rc = pthread_create(&ctrl_thread, &ctrl_attr, ctrl_func, NULL); #else rc = pthread_create(&ctrl_thread, NULL, ctrl_func, NULL); #endif check_err("pthread_create()\n", rc); #ifdef USE_EXPLICIT_SCHED memset(&calc_param, 0 , sizeof(calc_param)); pthread_attr_init(&calc_attr); pthread_attr_setschedpolicy(&calc_attr, SCHED_FIFO); calc_param.sched_priority = CALC_PRIO; pthread_attr_setschedparam(&calc_attr, &calc_param); pthread_attr_setinheritsched(&calc_attr, PTHREAD_EXPLICIT_SCHED); rc = pthread_create(&calc_thread, &calc_attr, calc_func, NULL); #else rc = pthread_create(&calc_thread, NULL, calc_func, NULL); #endif check_err("pthread_create()\n", rc); rc = pthread_join(calc_thread, &status); check_err("pthread_join()\n", rc); if (status != PTHREAD_CANCELED) printf("Unexpected thread status\n"); printf("main terminating in 2 seconds...\n"); sleep(3); return 0; }
APP := cancel-test CFLAGS = -Wall -O0 -g ifeq ($(XENO),) CC = gcc LDFLAGS = -lpthread -lrt else XENOCONFIG = \ $(shell PATH=$(XENO):$(XENO)/bin:$(PATH) which xeno-config 2>/dev/null) CC = $(shell $(XENOCONFIG) --cc) LD = $(patsubst %-gcc,%-ld,$(CC)) CFLAGS += $(shell $(XENOCONFIG) --posix-cflags) LDFLAGS = $(shell $(XENOCONFIG) --posix-ldflags) -lrtdk LDFLAGS += -Xlinker -rpath -Xlinker $(shell $(XENOCONFIG) --libdir) endif all: $(APP) $(APP): % : %.c $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) clean: $(RM) $(APP)
_______________________________________________ Xenomai-help mailing list Xenomai-help@gna.org https://mail.gna.org/listinfo/xenomai-help