/*
* linux/kernel/signal.c
*
* (C) 1991 Linus Torvalds
*/

#include <linux/sched.h>	// ȳͷļṹtask_structʼ0 ݣ
// һЩйúͻȡǶʽຯ䡣
#include <linux/kernel.h>	// ںͷļһЩں˳úԭζ塣
#include <asm/segment.h>	// βͷļйضμĴǶʽຯ

#include <signal.h>		// źͷļźŷųźŽṹԼźŲԭ͡

volatile void do_exit (int error_code);	// ǰ޶volatile ҪҪŻ

// ȡǰźλͼ룩
int
sys_sgetmask ()
{
  return current->blocked;
}

// µźλͼSIGKILL ܱΡֵԭźλͼ
int
sys_ssetmask (int newmask)
{
  int old = current->blocked;

  current->blocked = newmask & ~(1 << (SIGKILL - 1));
  return old;
}

// sigaction ݵfs ݶto 
static inline void
save_old (char *from, char *to)
{
  int i;

  verify_area (to, sizeof (struct sigaction));	// ֤to ڴǷ㹻
  for (i = 0; i < sizeof (struct sigaction); i++)
    {
      put_fs_byte (*from, to);	// Ƶfs ΡһûݶΡ
      from++;			// put_fs_byte()include/asm/segment.h С
      to++;
    }
}

// sigaction ݴfs ݶfrom λøƵto 
static inline void
get_new (char *from, char *to)
{
  int i;

  for (i = 0; i < sizeof (struct sigaction); i++)
    *(to++) = get_fs_byte (from++);
}

// signal()ϵͳásigaction()ΪָźŰװµźž(źŴ)
// źžûָĺҲSIG_DFLĬϾSIG_IGNԣ
// signum --ָźţhandler -- ָľrestorer Cԭǰִеĵַλá
// ԭźž
int
sys_signal (int signum, long handler, long restorer)
{
  struct sigaction tmp;

  if (signum < 1 || signum > 32 || signum == SIGKILL)	// źֵҪڣ1-32Χڣ
    return -1;			// ҲSIGKILL
  tmp.sa_handler = (void (*)(int)) handler;	// ָźŴ
  tmp.sa_mask = 0;		// ִʱź롣
  tmp.sa_flags = SA_ONESHOT | SA_NOMASK;	// þֻʹ1 κͻָĬֵ
// źԼĴյ
  tmp.sa_restorer = (void (*)(void)) restorer;	// 淵صַ
  handler = (long) current->sigaction[signum - 1].sa_handler;
  current->sigaction[signum - 1] = tmp;
  return handler;
}

// sigaction()ϵͳáıյһźʱĲsignum ǳSIGKILL κ
// źš[²(action)Ϊ]²װoldaction ָ벻Ϊգԭ
// oldactionɹ򷵻0Ϊ-1
int
sys_sigaction (int signum, const struct sigaction *action,
	       struct sigaction *oldaction)
{
  struct sigaction tmp;

// źֵҪڣ1-32ΧڣźSIGKILL Ĵܱı䡣
  if (signum < 1 || signum > 32 || signum == SIGKILL)
    return -1;
// źŵsigaction ṹµĲ
  tmp = current->sigaction[signum - 1];
  get_new ((char *) action, (char *) (signum - 1 + current->sigaction));
// oldaction ָ벻ΪյĻԭָ뱣浽oldaction ָλá
  if (oldaction)
    save_old ((char *) &tmp, (char *) oldaction);
// źԼźžյΪ0αźš
  if (current->sigaction[signum - 1].sa_flags & SA_NOMASK)
    current->sigaction[signum - 1].sa_mask = 0;
  else
    current->sigaction[signum - 1].sa_mask |= (1 << (signum - 1));
  return 0;
}

// ϵͳжϴźŴkernel/system_call.s,119 У
// öδҪǽźŵĴ뵽ûջУڱϵͳý
// غִźžȻִûĳ
void
do_signal (long signr, long eax, long ebx, long ecx, long edx,
	   long fs, long es, long ds,
	   long eip, long cs, long eflags, unsigned long *esp, long ss)
{
  unsigned long sa_handler;
  long old_eip = eip;
  struct sigaction *sa = current->sigaction + signr - 1;	//current->sigaction[signu-1]
  int longs;
  unsigned long *tmp_esp;

  sa_handler = (unsigned long) sa->sa_handler;
// źžΪSIG_IGN()򷵻أΪSIG_DFL(Ĭϴ)ź
// SIGCHLD 򷵻أ̵ִֹ
  if (sa_handler == 1)
    return;
  if (!sa_handler)
    {
      if (signr == SIGCHLD)
	return;
      else
	do_exit (1 << (signr - 1));	// [?? ΪʲôźλͼΪΪʲô!?]
// Ӧdo_exit(1<<signr))
    }
// źžֻʹһΣ򽫸þÿ(źžѾsa_handler ָ)
  if (sa->sa_flags & SA_ONESHOT)
    sa->sa_handler = NULL;
// δ뽫źŴ뵽ûջУͬʱҲsa_restorer,signr,(
// SA_NOMASK ûλ),eax,ecx,edx ΪԼԭϵͳõĳ򷵻ָ뼰־Ĵֵ
// ѹջڱϵͳж(0x80)ûʱִûźžȻ
// ټִû
// ûϵͳõĴָeip ָźŴ
  *(&eip) = sa_handler;
// źԼĴյźԼҲҪ̵ѹջ
  longs = (sa->sa_flags & SA_NOMASK) ? 7 : 8;
// ԭóûĶջָչ78֣ŵźžĲȣ
// ڴʹڴ泬ҳȣ
  *(&esp) -= longs;
  verify_area (esp, longs * 4);
// ûջдµϴsa_restorer, źsignr, blocked(SA_NOMASK λ),
// eax, ecx, edx, eflags ûԭָ롣
  tmp_esp = esp;
  put_fs_long ((long) sa->sa_restorer, tmp_esp++);
  put_fs_long (signr, tmp_esp++);
  if (!(sa->sa_flags & SA_NOMASK))
    put_fs_long (current->blocked, tmp_esp++);
  put_fs_long (eax, tmp_esp++);
  put_fs_long (ecx, tmp_esp++);
  put_fs_long (edx, tmp_esp++);
  put_fs_long (eflags, tmp_esp++);
  put_fs_long (old_eip, tmp_esp++);
  current->blocked |= sa->sa_mask;	// ()sa_mask еλ
}
