Hi Gilles,

Gilles Chanteperdrix wrote:
> On Dec 6, 2007 3:05 PM, Wolfgang Grandegger <[EMAIL PROTECTED]> wrote:
>> Gilles Chanteperdrix wrote:
>>> On Dec 6, 2007 2:28 PM, Gilles Chanteperdrix
>>> <[EMAIL PROTECTED]> wrote:
>>>> On Dec 6, 2007 2:24 PM, Wolfgang Grandegger <[EMAIL PROTECTED]> wrote:
>>>>> Gilles Chanteperdrix wrote:
>>>>>> On Dec 6, 2007 1:31 PM, Wolfgang Grandegger <[EMAIL PROTECTED]> wrote:
>>>>>>> Hello,
>>>>>>>
>>>>>>> how do I cancel or delete a Xenomai POSIX thread running in primary
>>>>>>> context from a higher priority thread? IIUC, pthread_kill() can only be
>>>>>>> used in secondary context. I tried pthread_cancel(), but it only works
>>>>>>> when hitting a cancelation point, e.g. pthread_testcancel(). Setting
>>>>>>> pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS) did not help. Is
>>>>>>> there a code snippet or even an example program showing how to cancel a
>>>>>>> pthread in primary context?
>>>>>> pthread_kill or pthread_cancel should result in sending a signal to
>>>>>> the target thread, so should cause this thread to switch to secondary
>>>>>> mode to handle it. If you want to wait for the target thread to be
>>>>>> canceled, you should use pthread_cancel and pthread_join.
>>>>> There is no way to cancel a pthread in primary mode from another pthread?
>>>> No. You always need secondary mode to effectively delete a thread. The
>>>> same goes for the native skin.
>>> Ok. I understand what you mean. You want pthread_cancel not to leave
>>> primary mode. This can easily be done by causing pthread_cancel to use
>>> the kernel-space real-time pthread_cancel service. This should work
>>> with no further modification.
>> I want to cancel/delete a task running in primary mode, e.g.
>>
>>   void* work_task(void* dummy)
>>   {
>>         int count = 0;
>>         while (1)
>>                 count++;
>>   }
>>
>> from the outside (= another higher priority task). How can I use the
>> kernel-space real-time pthread_cancel service? My POSIX app is runs in
>> user-land.
> 
> I was thinking about adding a pthread_cancel syscall that would have
> triggered the kernel-space pthread_cancel. But this will not work:
> user-space cleanup handlers would no longer get executed. However,
> this can work for pthread_kill. Here is a patch which adds the
> pthread_kill syscall.

Great, thanks a lot. This seems to work but I'm now fiddling with proper
cleanup and exit. I have attached my small test program. It behaves
somehow strange, at least to me:

- I see task period overruns when the low prio task is started. I
  suspect some switch to secondary mode in init_task().

- The program/system hangs after the listed messages:

  # ./kill_pthread
  Starting high_prio_task
  Killed low_prio task: count=3813129, overruns=0

Any idea what I'm doing wrong?

This is with Linux 2.4.25 and Xenomai 2.3.x on a MPC5200 board.

TIA.

Wolfgang.

#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <sys/mman.h>

static int count;

static pthread_t id_low;
static pthread_t id_high;

#define LOW_PRIO 5
#define HIGH_PRIO 10

#undef WITH_PRINTF
#undef WITH_SIGXCPU

void init_task(int prio);

void* low_prio_task(void* dummy)
{

   while (1)
   {
#ifdef WITH_PRINTF
	   printf("%s %d\n", __FUNCTION__, count);
#endif
	   count++;
   }
   printf("Exiting %s, count=%d\n", __FUNCTION__, count);
   return 0;
}

void* high_prio_task(void* dummy)
{
	struct timespec tstart = { .tv_sec = 0, .tv_nsec = 0};
#ifdef WITH_PRINTF
	struct timespec tperiod = { .tv_sec = 0, .tv_nsec = 10000000 };
#else
	struct timespec tperiod = { .tv_sec = 0, .tv_nsec = 1000000 };
#endif
	unsigned long overruns = 0;
	int tick = 0, step = 0, loop = 0, err;

	printf("Starting %s\n", __FUNCTION__);

#ifdef WITH_SIGXCPU
	pthread_set_mode_np(0, PTHREAD_WARNSW);
#endif
	err = pthread_make_periodic_np(pthread_self(), &tstart, &tperiod);
	if (err)
		return (void *)err;

	while (1) {
		err = pthread_wait_np(&overruns);
#if 0
		if (err) {
			pthread_kill(id_low, SIGSTOP);
			printf("%s overruns=%lu, tick=%d, count=%d, err=%d\n",
			       __FUNCTION__, overruns, tick, count, err);
			return 0;
		}
#endif
		if  (step == 0 && loop > 100) {
			loop = 0;
			step = 1;
			init_task(LOW_PRIO);
		}
		else if (step == 1 && loop > 50) {
			loop = 0;
			step = 0;
			pthread_kill(id_low, SIGSTOP);
			printf("Killed low_prio task: count=%d, overruns=%lu\n",
			       count, overruns);
			return 0;
		}
		tick++;
		loop++;
	}
	printf("Exiting %s\n", __FUNCTION__);
	return 0;
}

void init_task(int prio)
{
   struct sched_param parm;
   pthread_attr_t attr;

   pthread_attr_init(&attr);
   if (prio == HIGH_PRIO)
	   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
   else
	   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
   pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
   parm.sched_priority = prio;
   pthread_attr_setschedparam(&attr, &parm);

   if (prio == HIGH_PRIO) {
	   pthread_create(&id_high, &attr, high_prio_task, NULL);
	   pthread_set_name_np(id_high,"high_prio");
   } else {
	   pthread_create(&id_low, &attr, low_prio_task, NULL);
	   pthread_set_name_np(id_low,"low_prio");
   }
}

void catch_signal(int sig)
{
	printf("Signal %d catched\n", sig);
}

#ifdef WITH_SIGXCPU
void catch_switch(int sig)
{
	void *bt[32];
	int nentries;

	printf("Signal %d catched\n", sig);

	/* 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[])
{
	mlockall(MCL_CURRENT|MCL_FUTURE);

	signal(SIGTERM, catch_signal);
	signal(SIGINT, catch_signal);
	signal(SIGHUP, catch_signal);
#ifdef WITH_SIGXCPU
	signal(SIGXCPU, catch_switch);
#endif
	init_task(HIGH_PRIO);

	pthread_join(id_high, NULL);

	printf("Exiting %s\n", __FUNCTION__);
	return 0;
}
_______________________________________________
Xenomai-core mailing list
Xenomai-core@gna.org
https://mail.gna.org/listinfo/xenomai-core

Reply via email to