#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
#include <sys/time.h>
/* Buna sinyal eylemci atama yapacak. */
static volatile int expired;
/* Bağlamlar. */
static ucontext_t uc[3];
/* Biz belli sayıda geçiş yapacağız. */
static int switches;
/* Bu işi yapan işlev. Sadece bir iskelet,
gerçek kod sonra yerleştirilecek. */
static void
f (int n)
{
int m = 0;
while (1)
{
/* İşin yapıldığı yer. */
if (++m % 100 == 0)
{
putchar ('.');
fflush (stdout);
}
/* Değişkenin zaman aşımına uğrayıp uğramadığına
düzenli olarak bakmak lazım. */
if (expired)
{
/* Kodun daha fazla çalışmasını istemiyoruz. */
if (++switches == 20)
return;
printf ("\n%d. bağlamdan %d. bağlama geçiliyor\n", n, 3 - n);
expired = 0;
/* Diğer bağlama geçip şimdikini kaydedelim. */
swapcontext (&uc[n], &uc[3 - n]);
}
}
}
/* Sadece değişkene değer atayan bir sinyal eylemci bu. */
void
handler (int signal)
{
expired = 1;
}
int
main (void)
{
struct sigaction sa;
struct itimerval it;
char st1[8192];
char st2[8192];
/* Zamanlayıcının kullanacağı veri yapılarını ilklendirelim. */
sa.sa_flags = SA_RESTART;
sigfillset (&sa.sa_mask);
sa.sa_handler = handler;
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 1;
it.it_value = it.it_interval;
/* Zamanlayıcıyı kuralım ve çalışacağımız bağlamı alalım. */
if (sigaction (SIGPROF, &sa, NULL) < 0
|| setitimer (ITIMER_PROF, &it, NULL) < 0
|| getcontext (&uc[1]) == -1
|| getcontext (&uc[2]) == -1)
abort ();
/* Bağlamı, f işlevinin 1 parametresi ile çağrılmasına
sebep olan ayrı bir yığıt ile oluşturalım.
uc_link'in, işlev döndüğü anda yazılımın sonlanmasına
sebep olan ana bağlamı gösterdiğine dikkat edin. */
uc[1].uc_link = &uc[0];
uc[1].uc_stack.ss_sp = st1;
uc[1].uc_stack.ss_size = sizeof st1;
makecontext (&uc[1], (void (*) (void)) f, 1, 1);
/* Aynı ama f'ye parametre olarak 2 aktarılıyor. */
uc[2].uc_link = &uc[0];
uc[2].uc_stack.ss_sp = st2;
uc[2].uc_stack.ss_size = sizeof st2;
makecontext (&uc[2], (void (*) (void)) f, 1, 2);
/* İşbaşı! */
swapcontext (&uc[0], &uc[1]);
putchar ('\n');
return 0;
}