`

Linux信号功能的实现

阅读更多
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,
严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
1. 前言

信号是类UNIX系统中一个重要的进程控制方法,向中断一样,可通过向进程发送不同的信号临时中断
程序的正常运行而进入信号处理程序或执行缺省的信号响应,如重新更新程序配置、终止进程等。

在用户空间中,信号处理接口是通过一系列系统调用来实现的,包括signal, sigaction,
sigsuspend, sigaltstack等,进程可通过以上这些接口定义进程的信号处理函数。如果要向其他进
程发信号,可通过kill系统调用实现。

在内核中对信号的处理程序主要定义在 kernel/signal.c, arch/***/kernel/signal.c等文件中,头
文件在 include/linux/signal.h, include/asm/signal.h等。
 
以下内核代码版本为2.6.19.2。
 
2. 数据结构

2.1 信号自身基本定义

用于定义信号处理

/* include/asm-generic/signal.h */
// 信号处理函数格式
typedef void __signalfn_t(int);
typedef __signalfn_t __user *__sighandler_t;
// 信号恢复函数
typedef void __restorefn_t(void);
typedef __restorefn_t __user *__sigrestore_t;
// 三个预定义的信号处理函数值
#define SIG_DFL ((__force __sighandler_t)0) /* default signal handling */
#define SIG_IGN ((__force __sighandler_t)1) /* ignore signal */
#define SIG_ERR ((__force __sighandler_t)-1) /* error return from signal */
 
/* include/asm-i386/signal.h */
#define _NSIG  64
#define _NSIG_BPW 32
#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
typedef unsigned long old_sigset_t;  /* at least 32 bits */
// 信号集, 最多64个信号
typedef struct {
 unsigned long sig[_NSIG_WORDS];
} sigset_t;

// 老的信号处理结构
struct old_sigaction {
 __sighandler_t sa_handler;
 old_sigset_t sa_mask;
 unsigned long sa_flags;
 __sigrestore_t sa_restorer;
};
// 信号处理结构
struct sigaction {
// 信号处理函数
 __sighandler_t sa_handler;
// 标志
 unsigned long sa_flags;
// 信号恢复函数
 __sigrestore_t sa_restorer;
// 信号集
 sigset_t sa_mask;  /* mask last for extensibility */
};
// 另一个定义
struct k_sigaction {
 struct sigaction sa;
};

2.2 信号信息结构定义
用于发送信号

/* include/asm-generic/siginfo.h */
typedef struct siginfo {
 int si_signo;
 int si_errno;
 int si_code;
 union {
  int _pad[SI_PAD_SIZE];
  /* kill() */
  struct {
   pid_t _pid;  /* sender's pid */
   __ARCH_SI_UID_T _uid; /* sender's uid */
  } _kill;
  /* POSIX.1b timers */
  struct {
   timer_t _tid;  /* timer id */
   int _overrun;  /* overrun count */
   char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
   sigval_t _sigval; /* same as below */
   int _sys_private;       /* not to be passed to user */
  } _timer;
  /* POSIX.1b signals */
  struct {
   pid_t _pid;  /* sender's pid */
   __ARCH_SI_UID_T _uid; /* sender's uid */
   sigval_t _sigval;
  } _rt;
  /* SIGCHLD */
  struct {
   pid_t _pid;  /* which child */
   __ARCH_SI_UID_T _uid; /* sender's uid */
   int _status;  /* exit code */
   clock_t _utime;
   clock_t _stime;
  } _sigchld;
  /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
  struct {
   void __user *_addr; /* faulting insn/memory ref. */
#ifdef __ARCH_SI_TRAPNO
   int _trapno; /* TRAP # which caused the signal */
#endif
  } _sigfault;
  /* SIGPOLL */
  struct {
   __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */
   int _fd;
  } _sigpoll;
 } _sifields;
} siginfo_t;
 
3. 定义信号处理函数

signal系统调用在内核中对应的是sys_signal,sigaction对应的是sys_sysaction:

/* kernel/signal.c */
/*
 * For backwards compatibility.  Functionality superseded by sigaction.
 */
// signal函数已经只是为了后向兼容了,以后尽量还是使用sigaction实现为好
asmlinkage unsigned long
sys_signal(int sig, __sighandler_t handler)
{
 struct k_sigaction new_sa, old_sa;
 int ret;
// 填写新的信号处理结构参数
// 最重要的是handler参数
 new_sa.sa.sa_handler = handler;
 new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK;
 sigemptyset(&new_sa.sa.sa_mask);
// 进入do_sigaction函数处理
 ret = do_sigaction(sig, &new_sa, &old_sa);
// 如果返回值为0(成功), 返回原来的信号处理函数
 return ret ? ret : (unsigned long)old_sa.sa.sa_handler;
}
 
/* arch/i386/kernel/signal.c */
// 注意输入的是老的信号处理结构
asmlinkage int
sys_sigaction(int sig, const struct old_sigaction __user *act,
       struct old_sigaction __user *oact)
{
 struct k_sigaction new_ka, old_ka;
 int ret;
// act相当于新的信号处理结构定义
 if (act) {
// 从用户层空间拷贝信号处理结构参数
  old_sigset_t mask;
  if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
      __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
      __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
   return -EFAULT;
  __get_user(new_ka.sa.sa_flags, &act->sa_flags);
  __get_user(mask, &act->sa_mask);
  siginitset(&new_ka.sa.sa_mask, mask);
 }
// 进入do_sigaction函数处理
 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);

// 返回值为0(成功)时,返回老的信号处理结构信息
 if (!ret && oact) {
  if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
      __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
      __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
   return -EFAULT;
  __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
  __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
 }
 return ret;
}

这两个函数基本相同, 但一个是只处理一个信号处理函数,另一个则是处理一个信号处理结构, 参数
要复杂一些,但这两个函数的核心都是do_sysaction:

/* kernel/signal.c */
int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
{
 struct k_sigaction *k;
 sigset_t mask;
// 检查一下参数是否合法
 if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig)))
  return -EINVAL;
// k指向进程原来的信号处理结构
 k = &current->sighand->action[sig-1];
 spin_lock_irq(&current->sighand->siglock);
 if (signal_pending(current)) {
// 目前进程在信号处理状态中
// 此时不能设置信号处理程序
  /*
   * If there might be a fatal signal pending on multiple
   * threads, make sure we take it before changing the action.
   */
  spin_unlock_irq(&current->sighand->siglock);
  return -ERESTARTNOINTR;
 }
// 将进程原来的信号处理结构备份到函数参数指定的原信号处理结构中
 if (oact)
  *oact = *k;
// 要更新信号处理
 if (act) {
// SIGKILL和SIGSTOP这两个信号是不能定义新的处理函数的
// 相应标识始终被清除,因此即使设了也没用
  sigdelsetmask(&act->sa.sa_mask,
         sigmask(SIGKILL) | sigmask(SIGSTOP));
// 将新信号结构复制到进程对应的信号处理结构中
  *k = *act;
  /*
   * POSIX 3.3.1.3:
   *  "Setting a signal action to SIG_IGN for a signal that is
   *   pending shall cause the pending signal to be discarded,
   *   whether or not it is blocked."
   *
   *  "Setting a signal action to SIG_DFL for a signal that is
   *   pending and whose default action is to ignore the signal
   *   (for example, SIGCHLD), shall cause the pending signal to
   *   be discarded, whether or not it is blocked"
   */
  if (act->sa.sa_handler == SIG_IGN ||
     (act->sa.sa_handler == SIG_DFL && sig_kernel_ignore(sig))) {
// 如果新的信号处理函数是忽略该信号
   struct task_struct *t = current;
// 清空信号掩码
   sigemptyset(&mask);
// 设置掩码中相应信号的位
   sigaddset(&mask, sig);
// 从该进程的信号队列中清除该信号
   rm_from_queue_full(&mask, &t->signal->shared_pending);
// 从该进程的所有子线程的信号队列中清除该信号
   do {
    rm_from_queue_full(&mask, &t->pending);
    recalc_sigpending_tsk(t);
    t = next_thread(t);
   } while (t != current);
  }
 }
 spin_unlock_irq(&current->sighand->siglock);
 return 0;
}

4. 发送信号

发送信号是通过kill(2)系统调用实现的,内核对应的处理函数是sys_kill:
/* kernel/signal.c */
asmlinkage long
sys_kill(int pid, int sig)
{
 struct siginfo info;
// 填写信号信息结构参数, 该结构使用前没清零,也没用填满结构中所有参数
// 信号值
 info.si_signo = sig;
 info.si_errno = 0;
 info.si_code = SI_USER;
 info.si_pid = current->tgid;
 info.si_uid = current->uid;
// 向pid进程发送信号
 return kill_something_info(sig, &info, pid);
}

/* kernel/signal.h */
/*
 * kill_something_info() interprets pid in interesting ways just like kill(2).
 *
 * POSIX specifies that kill(-1,sig) is unspecified, but what we have
 * is probably wrong.  Should make it like BSD or SYSV.
 */
static int kill_something_info(int sig, struct siginfo *info, int pid)
{
 if (!pid) {
// pid为0, 是向一个进程组发信号
  return kill_pg_info(sig, info, process_group(current));
 } else if (pid == -1) {
// pid为-1. 向所有其他组的进程发送信号
  int retval = 0, count = 0;
  struct task_struct * p;
  read_lock(&tasklist_lock);
  for_each_process(p) {
   if (p->pid > 1 && p->tgid != current->tgid) {
    int err = group_send_sig_info(sig, info, p);
    ++count;
    if (err != -EPERM)
     retval = err;
   }
  }
  read_unlock(&tasklist_lock);
  return count ? retval : -ESRCH;
 } else if (pid < 0) {
// 其他的负pid值,将pid取反为正值后向进程组发送信号
  return kill_pg_info(sig, info, -pid);
 } else {
// 一般情况, 向指定pid的进程发送信号
  return kill_proc_info(sig, info, pid);
 }
}

函数调用流程图:
kill_proc_info        kill_pg_info
     |                      |
     V                      V
kill_pid_info         __kill_pg_info
     |                      |
     |                      V
     |                __kill_pgrp_info
     |                      |
     +----------------------+
                |
                V
        group_send_sig_info
                |
                V
        __group_send_sig_info
                |
                V
            send_signal

/* kernel/signal.c */
static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
   struct sigpending *signals)
{
 struct sigqueue * q = NULL;
 int ret = 0;
 /*
  * fast-pathed signals for kernel-internal things like SIGSTOP
  * or SIGKILL.
  */
// 强制发送信号(SIGKILL或SIGSTOP), 直接发送
 if (info == SEND_SIG_FORCED)
  goto out_set;
 /* Real-time signals must be queued if sent by sigqueue, or
    some other real-time mechanism.  It is implementation
    defined whether kill() does so.  We attempt to do so, on
    the principle of least surprise, but since kill is not
    allowed to fail with EAGAIN when low on memory we just
    make sure at least one signal gets delivered and don't
    pass on the info struct.  */
// 分配信号队列结构, 从sigqueue_cachep中分配(这个一个kmem_cache)
 q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN &&
          (is_si_special(info) ||
           info->si_code >= 0)));
 if (q) {
// 分配成功
// 将该信号队列挂接到待发送信号链表末尾, 注意add_list是添加到链表头的
  list_add_tail(&q->list, &signals->list);
  switch ((unsigned long) info) {
// 先看是否是几个特殊的info值然后填写相应的信号信息结构参数
  case (unsigned long) SEND_SIG_NOINFO:
// 信号值
   q->info.si_signo = sig;
   q->info.si_errno = 0;
   q->info.si_code = SI_USER;
   q->info.si_pid = current->pid;
   q->info.si_uid = current->uid;
   break;
  case (unsigned long) SEND_SIG_PRIV:
// 信号值
   q->info.si_signo = sig;
   q->info.si_errno = 0;
   q->info.si_code = SI_KERNEL;
   q->info.si_pid = 0;
   q->info.si_uid = 0;
   break;
  default:
// 如是普通情况,复制信号信息
   copy_siginfo(&q->info, info);
   break;
  }
 } else if (!is_si_special(info)) {
// 队列满了,普通用户的信号就被忽略,返回错误
  if (sig >= SIGRTMIN && info->si_code != SI_USER)
  /*
   * Queue overflow, abort.  We may abort if the signal was rt
   * and sent by user using something other than kill().
   */
   return -EAGAIN;
 }
out_set:
// 设置信号集中相应的信号标志
 sigaddset(&signals->signal, sig);
 return ret;
}

/* include/asm-i386/signal.h */
#define sigaddset(set,sig)                 \
 (__builtin_constant_p(sig) ?       \
 __const_sigaddset((set),(sig)) :   \
 __gen_sigaddset((set),(sig)))
static __inline__ void __gen_sigaddset(sigset_t *set, int _sig)
{
 __asm__("btsl %1,%0" : "+m"(*set) : "Ir"(_sig - 1) : "cc");
}
static __inline__ void __const_sigaddset(sigset_t *set, int _sig)
{
 unsigned long sig = _sig - 1;
 set->sig[sig / _NSIG_BPW] |= 1 << (sig % _NSIG_BPW);
}

5. 处理信号

/* arch/i386/kernel/signal.c */
/*
 * notification of userspace execution resumption
 * - triggered by the TIF_WORK_MASK flags
 */
__attribute__((regparm(3)))
void do_notify_resume(struct pt_regs *regs, void *_unused,
        __u32 thread_info_flags)
{
 /* Pending single-step? */
 if (thread_info_flags & _TIF_SINGLESTEP) {
  regs->eflags |= TF_MASK;
  clear_thread_flag(TIF_SINGLESTEP);
 }
 /* deal with pending signal delivery */
// 派发待发送的信号
 if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
  do_signal(regs);
 
 clear_thread_flag(TIF_IRET);
}

/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 */
static void fastcall do_signal(struct pt_regs *regs)
{
 siginfo_t info;
 int signr;
 struct k_sigaction ka;
 sigset_t *oldset;
 /*
  * We want the common case to go fast, which
  * is why we may in certain cases get here from
  * kernel mode. Just return without doing anything
   * if so.  vm86 regs switched out by assembly code
   * before reaching here, so testing against kernel
   * CS suffices.
  */
// 信号处理函数是在用户空间
 if (!user_mode(regs))
  return;
// 原先的信息集指针
 if (test_thread_flag(TIF_RESTORE_SIGMASK))
  oldset = &current->saved_sigmask;
 else
  oldset = &current->blocked;
// 找要发送的信号
 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 if (signr > 0) {
// 找到一个信号
  /* Reenable any watchpoints before delivering the
   * signal to user space. The processor register will
   * have been cleared if the watchpoint triggered
   * inside the kernel.
   */
  if (unlikely(current->thread.debugreg[7]))
   set_debugreg(current->thread.debugreg[7], 7);
  /* Whee!  Actually deliver the signal.  */
// 处理信号
  if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
   /* a signal was successfully delivered; the saved
    * sigmask will have been stored in the signal frame,
    * and will be restored by sigreturn, so we can simply
    * clear the TIF_RESTORE_SIGMASK flag */
   if (test_thread_flag(TIF_RESTORE_SIGMASK))
    clear_thread_flag(TIF_RESTORE_SIGMASK);
  }
  return;
 }
// 无信号的情况
 /* Did we come from a system call? */
 if (regs->orig_eax >= 0) {
  /* Restart the system call - no handlers present */
  switch (regs->eax) {
  case -ERESTARTNOHAND:
  case -ERESTARTSYS:
  case -ERESTARTNOINTR:
   regs->eax = regs->orig_eax;
   regs->eip -= 2;
   break;
  case -ERESTART_RESTARTBLOCK:
   regs->eax = __NR_restart_syscall;
   regs->eip -= 2;
   break;
  }
 }
 /* if there's no signal to deliver, we just put the saved sigmask
  * back */
 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
  clear_thread_flag(TIF_RESTORE_SIGMASK);
  sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
 }
}

/*
 * OK, we're invoking a handler
 */ 
static int
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
       sigset_t *oldset, struct pt_regs * regs)
{
 int ret;
 /* Are we from a system call? */
 if (regs->orig_eax >= 0) {
// 判断当前是否在系统调用中
  /* If so, check system call restarting.. */
  switch (regs->eax) {
          case -ERESTART_RESTARTBLOCK:
   case -ERESTARTNOHAND:
    regs->eax = -EINTR;
    break;
   case -ERESTARTSYS:
    if (!(ka->sa.sa_flags & SA_RESTART)) {
     regs->eax = -EINTR;
     break;
    }
   /* fallthrough */
   case -ERESTARTNOINTR:
    regs->eax = regs->orig_eax;
    regs->eip -= 2;
  }
 }
 /*
  * If TF is set due to a debugger (PT_DTRACE), clear the TF flag so
  * that register information in the sigcontext is correct.
  */
 if (unlikely(regs->eflags & TF_MASK)
     && likely(current->ptrace & PT_DTRACE)) {
  current->ptrace &= ~PT_DTRACE;
  regs->eflags &= ~TF_MASK;
 }
 /* Set up the stack frame */
// 建立进入信号处理函数前堆栈帧
 if (ka->sa.sa_flags & SA_SIGINFO)
  ret = setup_rt_frame(sig, ka, info, oldset, regs);
 else
  ret = setup_frame(sig, ka, oldset, regs);
 if (ret == 0) {
  spin_lock_irq(&current->sighand->siglock);
  sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
  if (!(ka->sa.sa_flags & SA_NODEFER))
   sigaddset(&current->blocked,sig);
  recalc_sigpending();
  spin_unlock_irq(&current->sighand->siglock);
 }
 return ret;
}
 
/* kernel/signal.c */
// 找要发送的信号
int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
     struct pt_regs *regs, void *cookie)
{
 sigset_t *mask = &current->blocked;
 int signr = 0;
 try_to_freeze();
relock:
 spin_lock_irq(&current->sighand->siglock);
 for (;;) {
  struct k_sigaction *ka;
// unlikely的处理就是大部分情况下可忽略
  if (unlikely(current->signal->group_stop_count > 0) &&
      handle_group_stop())
   goto relock;
// 从当前进程的信号队列中取信号
  signr = dequeue_signal(current, mask, info);
  if (!signr)
// 无信号
   break; /* will return 0 */
// 有信号
  if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
// 当前进程是被跟踪调试中
   ptrace_signal_deliver(regs, cookie);
   /* Let the debugger run.  */
   ptrace_stop(signr, signr, info);
   /* We're back.  Did the debugger cancel the sig?  */
   signr = current->exit_code;
   if (signr == 0)
    continue;
   current->exit_code = 0;
   /* Update the siginfo structure if the signal has
      changed.  If the debugger wanted something
      specific in the siginfo structure then it should
      have updated *info via PTRACE_SETSIGINFO.  */
   if (signr != info->si_signo) {
    info->si_signo = signr;
    info->si_errno = 0;
    info->si_code = SI_USER;
    info->si_pid = current->parent->pid;
    info->si_uid = current->parent->uid;
   }
   /* If the (new) signal is now blocked, requeue it.  */
   if (sigismember(&current->blocked, signr)) {
    specific_send_sig_info(signr, info, current);
    continue;
   }
  }
// 获取当前进程的信号处理函数
  ka = &current->sighand->action[signr-1];
  if (ka->sa.sa_handler == SIG_IGN) /* Do nothing.  */
// 该信号是要忽略的,重新找下一信号
   continue;
  if (ka->sa.sa_handler != SIG_DFL) {
// 定义了具体的函数处理函数, 复制要返回信号处理结构
   /* Run the handler.  */
   *return_ka = *ka;
   if (ka->sa.sa_flags & SA_ONESHOT)
    ka->sa.sa_handler = SIG_DFL;
   break; /* will return non-zero "signr" value */
  }
  /*
   * Now we are doing the default action for this signal.
   */
// 否则执行系统缺省的信号处理
  if (sig_kernel_ignore(signr)) /* Default is nothing. */
   continue;
  /* Init gets no signals it doesn't want.  */
  if (current == child_reaper)
   continue;
  if (sig_kernel_stop(signr)) {
   /*
    * The default action is to stop all threads in
    * the thread group.  The job control signals
    * do nothing in an orphaned pgrp, but SIGSTOP
    * always works.  Note that siglock needs to be
    * dropped during the call to is_orphaned_pgrp()
    * because of lock ordering with tasklist_lock.
    * This allows an intervening SIGCONT to be posted.
    * We need to check for that and bail out if necessary.
    */
   if (signr != SIGSTOP) {
    spin_unlock_irq(&current->sighand->siglock);
    /* signals can be posted during this window */
    if (is_orphaned_pgrp(process_group(current)))
     goto relock;
    spin_lock_irq(&current->sighand->siglock);
   }
   if (likely(do_signal_stop(signr))) {
    /* It released the siglock.  */
    goto relock;
   }
   /*
    * We didn't actually stop, due to a race
    * with SIGCONT or something like that.
    */
   continue;
  }
  spin_unlock_irq(&current->sighand->siglock);
  /*
   * Anything else is fatal, maybe with a core dump.
   */
  current->flags |= PF_SIGNALED;
  if (sig_kernel_coredump(signr)) {
   /*
    * If it was able to dump core, this kills all
    * other threads in the group and synchronizes with
    * their demise.  If we lost the race with another
    * thread getting here, it set group_exit_code
    * first and our do_group_exit call below will use
    * that value and ignore the one we pass it.
    */
   do_coredump((long)signr, signr, regs);
  }
  /*
   * Death signals, no core dump.
   */
  do_group_exit(signr);
  /* NOTREACHED */
 }
 spin_unlock_irq(&current->sighand->siglock);
 return signr;
}

6. 结论

Linux下的信号实现基本符合了APUE中对信号处理的描述, SIGKILL/SIGSTOP不可忽略, 发送给某进程的信号会排队, 信号可能会丢失等等.
分享到:
评论

相关推荐

    Linux信号量实现异名进程同步代码

    该文档介绍了如何在linux操作系统中使用信号量实现不同进程间的同步功能。

    Linuxc 信号的使用

    1.编程实现以下功能: 主线程实现以下功能: ① 定义全局变量key; ② 创建两个线程; ③ 如果线程正常结束,得到线程的结束状态值,并打印; 线程一完成以下操作: ① 设置全局变量key的值为字符串“hello world”...

    Linux 0.11下信号量的简单实现——用生产者消费者做检验

    这是一个在Linux 0.11下简单的信号量的实现,笔者只做了信号量最基本的功能,包括几乎所有要改动的文件。

    unix/linux下多线程/信号管理框架

    自己实现的一个简单的unix/linux下多线程、信号的管理框架,使用者只需考虑实现自己的功能即可,不需考虑多线程、ctrl+c的信号维护,已在aix6.1和turbo linux下通过测试

    本科毕业论文 Linux下文件管理与文件传送的研究与实现

    本科毕业论文 Linux下文件管理与文件传送的研究与实现 目 录 摘 要 III 关键词 III Abstract III Key words III 前言 1 1 Linux操作系统 1 1.1 Linux操作系统的产生及发展 1 1.2 Linux操作系统的特点 3 1.2.1自由...

    Linux课程设计:多线程停车场,使用锁和信号量实现,引入pthread-win32库后,可以在windows下运行+源代码+文

    Linux课程设计:多线程停车场,使用锁和信号量实现,引入pthread-win32库后,可以在windows下运行+源代码+文 - 小白不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行...

    基于Linux消息队列的简易聊天室(C语言)(附源代码)

    Linux IPC通信利用消息队列消息机制,多线程通信,字符串处理,链表操作,信号简单处理。消息队列是System V支持一种IPC机制,通过类似链表的操作向一个FIFO里通过msgsnd发送用户自定义数据,进程可以通过msgrcv来...

    研究论文-基于S3C2410的嵌入式Linux车载信息终端实现.pdf

    通过分析车载终端功能需求,实现了基于CAN(控制器局域网)和SAE J1939协议的汽车信号采集与解析、GPS(全球定位系统)定位信息采集与解析以及GPRS(通用无线分组业务)数据传输等功能模块的软件设计,并基于嵌入式...

    共享内存实现,带信号量互斥

    linux下共享内存实现 带信号量 互斥锁,功能描述:每次从文件中读取50*M + N*33 bytes, 其中M,N是{1, 2, 5, 9, 13, 17, 19}中的随机数。随机从共享内存中读取20bytes。

    Linux下0.1版本具有聊天功能的小程序

    使用多进程,共享内存,信号等方式,做了一个聊天的小程序,有makefile,可以直接在vscode里面调试

    亲测可用基于Linux消息队列的简易聊天室(C语言).zip

    Linux IPC通信利用消息队列消息机制,多线程通信,字符串处理,链表操作,信号简单处理。消息队列是System V支持一种IPC机制,通过类似链表的操作向一个FIFO里通过msgsnd发送用户自定义数据,进程可以通过msgrcv来...

    Linux进程间通信–使用信号

    同样的功能在Linux上是通过生成信号和捕获信号来实现的,运行中的进程捕获到这个信号然后作出一定的操作并最终被终止。 信号是UNIX和Linux系统响应某些条件而产生的一个事件,接收到该信号的进程会相应地采取一些...

    信号量应用

    linux 下c编程,通过信号量的应用实现发送进程和接收进程的数据访问

    嵌入式Linux基本实验代码

    创建多个线程(打印创建线程的序号);...使用信号量实现同步操作; 使用信号量实现互斥操作; 使用消息队列实现通信功能; 使用管道实现通信功能; 实现函数的周期执行; 使用Socket实现客户机服务器模型

    linux中一个程序的两个线程的同步(c语言实现)

    两个线程共享变量a,一个负责加一,一个负责输出 通过信号灯的pv操作完成

    嵌入式Linux系统串口和AD转换器编程

    利用外部模拟信号编程实现 ARM 循环采集全部前 4 路通道,并且在超级终端上显示。 了解在 linux 环境下对 S3C2410 芯片的 8 通道 10 位 A/D 的操作与控制。理解总个实验的原理,能按步骤做出实验,得到实验结果,并...

    《C 语言实现 Linux Shell 命令解释器》项目.zip

    另外还能深入到底层理解 Linux Shell 的功能的实现手段。 软件开发设计:应用软件开发、系统软件开发、移动应用开发、网站开发C++、Java、python、web、C#等语言的项目开发与学习资料 硬件与设备:单片机、EDA、...

    sem_syn.rar_linux syn_信号量_线程 同步

    通过两个信号量来实现两个线程间的同步,完成了互斥功能.

    linux 内核源代码分析

    1. 1 Linux内核简介 1. 2 Intel X86 CPU系列的寻址方式 1. 3 i386的页式内存管理机制 1. 4 Linux内核源代码中的C语言代码 1.5 Linux内核源代码中的汇编语言代码 第2章 存储管理 2.1 Linux内存管理的基本框架...

    FTP服务器(linux)

    在linux下实现的FTP服务器,实现对文件上传下载等功能,主要运用:守护进程,线程,socket编程,管道,共享内存以及信号量等。

Global site tag (gtag.js) - Google Analytics