Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Kernels
 Boot 
 Memory 
 File system
 0.01
 1.0 
 2.0 
 2.4 
 2.6 
 3.x 
 4.x 
 5.x 
 6.x 
 Интервью 
 Kernel
 HOW-TO 1
 Ptrace
 Kernel-Rebuild-HOWTO
 Runlevel
 Linux daemons
 FAQ
NEWS
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 Secure Programming for Li...6501 
 Linux Kernel 2.6...5278 
 Trees...1112 
 Максвелл 3...1046 
 William Gropp...984 
 Go Web ...953 
 Ethreal 3...921 
 Gary V.Vaughan-> Libtool...911 
 Ethreal 4...908 
 Ext4 FS...898 
 Clickhouse...896 
 Rodriguez 6...895 
 Ethreal 1...888 
 Steve Pate 1...877 
 C++ Patterns 3...858 
 Assembler...845 
 Ulrich Drepper...838 
 DevFS...779 
 MySQL & PosgreSQL...761 
 Стивенс 9...752 
 
  01.01.2024 : 3621733 посещений 

iakovlev.org

KernelAnalysis

Roberto Arcomano
 
   Copyright (C) 2000,2001,2002 Roberto Arcomano.
Директория /usr/src/linux подразумевается как стартовая В данном документе для рассмотрения того , как функции вызывают друг друга , используется т.н. префикс "InterCallings Analysis "(ICA)" , например , команда the sleep_on : color=blue> |sleep_on |init_waitqueue_entry -- |__add_wait_queue | enqueuing request |list_add | |__list_add -- |schedule --- waiting for request to be executed |__remove_wait_queue -- |list_del | dequeuing request |__list_del -- В примере function1 -> function2 < function1 > есть указатель на другую функцию . Когда мы пишем function: , то это как правило метка .

Итак , что же такое ядро ? Это сердцевина компьютерной системы , которая позволяет конечным пользователям использовать ресурсы компьютера , которая - как в случае с виндами - может включать в себя графическое управление . В чем разница между пользовательским режимом и режимом ядра ?
   1. Kernel Mode: в этом случае машина оперирует с критическими 
      структурами данных - памятью , маппмнгом , IRQ , DMA и т.д.
   2. User Mode: пользовательские приложения
Процессоры Intel могут находиться в 4-х состояниях - 0,1,2,3 , и 0 - это Kernel Mode. Линукс использует лишь 2 уровня из 4-х .
 Когда происходит переключение из одного режима в другой - как правило :
   1. При вызове System Call: вызывается код в Kernel Mode
   2. При генерации прерывания или исключения
 Системные функции могут быть вызваны при :
        когда происходит вызов I/O device или file
        когда нужно вычислить  pid, изменить scheduling policy
        вызов fork
        выполнение команды
Ниже представлен список System Calls для 2.4.17, [ arch/i386/kernel/entry.S ]
 long SYMBOL_NAME(sys_ni_syscall)/* 0  -  old "setup()" system call*/
           .long SYMBOL_NAME(sys_exit)
           .long SYMBOL_NAME(sys_fork)
           .long SYMBOL_NAME(sys_read)
           .long SYMBOL_NAME(sys_write)
           .long SYMBOL_NAME(sys_open)             /* 5 */
           .long SYMBOL_NAME(sys_close)
           .long SYMBOL_NAME(sys_waitpid)
           .long SYMBOL_NAME(sys_creat)
           .long SYMBOL_NAME(sys_link)
           .long SYMBOL_NAME(sys_unlink)           /* 10 */
           .long SYMBOL_NAME(sys_execve)
           .long SYMBOL_NAME(sys_chdir)
           .long SYMBOL_NAME(sys_time)
           .long SYMBOL_NAME(sys_mknod)
           .long SYMBOL_NAME(sys_chmod)            /* 15 */
           .long SYMBOL_NAME(sys_lchown16)
 long SYMBOL_NAME(sys_ni_syscall)/* old break syscall holder */
           .long SYMBOL_NAME(sys_stat)
           .long SYMBOL_NAME(sys_lseek)
           .long SYMBOL_NAME(sys_getpid)           /* 20 */
           .long SYMBOL_NAME(sys_mount)
           .long SYMBOL_NAME(sys_oldumount)
           .long SYMBOL_NAME(sys_setuid16)
           .long SYMBOL_NAME(sys_getuid16)
           .long SYMBOL_NAME(sys_stime)            /* 25 */
           .long SYMBOL_NAME(sys_ptrace)
           .long SYMBOL_NAME(sys_alarm)
           .long SYMBOL_NAME(sys_fstat)
           .long SYMBOL_NAME(sys_pause)
           .long SYMBOL_NAME(sys_utime)            /* 30 */
 .long SYMBOL_NAME(sys_ni_syscall)/* old stty syscall holder */
 .long SYMBOL_NAME(sys_ni_syscall)/* old gtty syscall holder */
           .long SYMBOL_NAME(sys_access)
           .long SYMBOL_NAME(sys_nice)
 .long SYMBOL_NAME(sys_ni_syscall) /* 35 */ 
                /* old ftime syscall holder */
           .long SYMBOL_NAME(sys_sync)
           .long SYMBOL_NAME(sys_kill)
           .long SYMBOL_NAME(sys_rename)
           .long SYMBOL_NAME(sys_mkdir)
           .long SYMBOL_NAME(sys_rmdir)            /* 40 */
           .long SYMBOL_NAME(sys_dup)
           .long SYMBOL_NAME(sys_pipe)
           .long SYMBOL_NAME(sys_times)
            /* old prof syscall holder */
           .long SYMBOL_NAME(sys_ni_syscall)
           .long SYMBOL_NAME(sys_brk)              /* 45 */
           .long SYMBOL_NAME(sys_setgid16)
           .long SYMBOL_NAME(sys_getgid16)
           .long SYMBOL_NAME(sys_signal)
           .long SYMBOL_NAME(sys_geteuid16)
           .long SYMBOL_NAME(sys_getegid16)        /* 50 */
           .long SYMBOL_NAME(sys_acct)
            /* recycled never used phys() */
           .long SYMBOL_NAME(sys_umount)
           /* old lock syscall holder */
           .long SYMBOL_NAME(sys_ni_syscall)                               
           .long SYMBOL_NAME(sys_ioctl)
           .long SYMBOL_NAME(sys_fcntl)            /* 55 */
             /* old mpx syscall holder */
           .long SYMBOL_NAME(sys_ni_syscall)                             
           .long SYMBOL_NAME(sys_setpgid)
           /* old ulimit syscall holder */
           .long SYMBOL_NAME(sys_ni_syscall)                               
           .long SYMBOL_NAME(sys_olduname)
           .long SYMBOL_NAME(sys_umask)            /* 60 */
           .long SYMBOL_NAME(sys_chroot)
           .long SYMBOL_NAME(sys_ustat)
           .long SYMBOL_NAME(sys_dup2)
           .long SYMBOL_NAME(sys_getppid)
           .long SYMBOL_NAME(sys_getpgrp)          /* 65 */
           .long SYMBOL_NAME(sys_setsid)
           .long SYMBOL_NAME(sys_sigaction)
           .long SYMBOL_NAME(sys_sgetmask)
           .long SYMBOL_NAME(sys_ssetmask)
           .long SYMBOL_NAME(sys_setreuid16)       /* 70 */
           .long SYMBOL_NAME(sys_setregid16)
           .long SYMBOL_NAME(sys_sigsuspend)
           .long SYMBOL_NAME(sys_sigpending)
           .long SYMBOL_NAME(sys_sethostname)
           .long SYMBOL_NAME(sys_setrlimit)        /* 75 */
           .long SYMBOL_NAME(sys_old_getrlimit)
           .long SYMBOL_NAME(sys_getrusage)
           .long SYMBOL_NAME(sys_gettimeofday)
           .long SYMBOL_NAME(sys_settimeofday)
           .long SYMBOL_NAME(sys_getgroups16)      /* 80 */
           .long SYMBOL_NAME(sys_setgroups16)
           .long SYMBOL_NAME(old_select)
           .long SYMBOL_NAME(sys_symlink)
           .long SYMBOL_NAME(sys_lstat)
           .long SYMBOL_NAME(sys_readlink)         /* 85 */
           .long SYMBOL_NAME(sys_uselib)
           .long SYMBOL_NAME(sys_swapon)
           .long SYMBOL_NAME(sys_reboot)
           .long SYMBOL_NAME(old_readdir)
           .long SYMBOL_NAME(old_mmap)             /* 90 */
           .long SYMBOL_NAME(sys_munmap)
           .long SYMBOL_NAME(sys_truncate)
           .long SYMBOL_NAME(sys_ftruncate)
           .long SYMBOL_NAME(sys_fchmod)
           .long SYMBOL_NAME(sys_fchown16)         /* 95 */
           .long SYMBOL_NAME(sys_getpriority)
           .long SYMBOL_NAME(sys_setpriority)
           /* old profil syscall holder */
           .long SYMBOL_NAME(sys_ni_syscall)                               
           .long SYMBOL_NAME(sys_statfs)
           .long SYMBOL_NAME(sys_fstatfs)          /* 100 */
           .long SYMBOL_NAME(sys_ioperm)
           .long SYMBOL_NAME(sys_socketcall)
           .long SYMBOL_NAME(sys_syslog)
           .long SYMBOL_NAME(sys_setitimer)
           .long SYMBOL_NAME(sys_getitimer)        /* 105 */
           .long SYMBOL_NAME(sys_newstat)
           .long SYMBOL_NAME(sys_newlstat)
           .long SYMBOL_NAME(sys_newfstat)
           .long SYMBOL_NAME(sys_uname)
           .long SYMBOL_NAME(sys_iopl)             /* 110 */
           .long SYMBOL_NAME(sys_vhangup)
           .long SYMBOL_NAME(sys_ni_syscall)/* old "idle" system call */
           .long SYMBOL_NAME(sys_vm86old)
           .long SYMBOL_NAME(sys_wait4)
           .long SYMBOL_NAME(sys_swapoff)          /* 115 */
           .long SYMBOL_NAME(sys_sysinfo)
           .long SYMBOL_NAME(sys_ipc)
           .long SYMBOL_NAME(sys_fsync)
           .long SYMBOL_NAME(sys_sigreturn)
           .long SYMBOL_NAME(sys_clone)            /* 120 */
           .long SYMBOL_NAME(sys_setdomainname)
           .long SYMBOL_NAME(sys_newuname)
           .long SYMBOL_NAME(sys_modify_ldt)
           .long SYMBOL_NAME(sys_adjtimex)
           .long SYMBOL_NAME(sys_mprotect)         /* 125 */
           .long SYMBOL_NAME(sys_sigprocmask)
           .long SYMBOL_NAME(sys_create_module)
           .long SYMBOL_NAME(sys_init_module)
           .long SYMBOL_NAME(sys_delete_module)
           .long SYMBOL_NAME(sys_get_kernel_syms)  /* 130 */
           .long SYMBOL_NAME(sys_quotactl)
           .long SYMBOL_NAME(sys_getpgid)
           .long SYMBOL_NAME(sys_fchdir)
           .long SYMBOL_NAME(sys_bdflush)
           .long SYMBOL_NAME(sys_sysfs)            /* 135 */
           .long SYMBOL_NAME(sys_personality)
           .long SYMBOL_NAME(sys_ni_syscall)       /* for afs_syscall */
           .long SYMBOL_NAME(sys_setfsuid16)
           .long SYMBOL_NAME(sys_setfsgid16)
           .long SYMBOL_NAME(sys_llseek)           /* 140 */
           .long SYMBOL_NAME(sys_getdents)
           .long SYMBOL_NAME(sys_select)
           .long SYMBOL_NAME(sys_flock)
           .long SYMBOL_NAME(sys_msync)
           .long SYMBOL_NAME(sys_readv)            /* 145 */
           .long SYMBOL_NAME(sys_writev)
           .long SYMBOL_NAME(sys_getsid)
           .long SYMBOL_NAME(sys_fdatasync)
           .long SYMBOL_NAME(sys_sysctl)
           .long SYMBOL_NAME(sys_mlock)            /* 150 */
           .long SYMBOL_NAME(sys_munlock)
           .long SYMBOL_NAME(sys_mlockall)
           .long SYMBOL_NAME(sys_munlockall)
           .long SYMBOL_NAME(sys_sched_setparam)
           .long SYMBOL_NAME(sys_sched_getparam)   /* 155 */
           .long SYMBOL_NAME(sys_sched_setscheduler)
           .long SYMBOL_NAME(sys_sched_getscheduler)
           .long SYMBOL_NAME(sys_sched_yield)
           .long SYMBOL_NAME(sys_sched_get_priority_max)
           .long SYMBOL_NAME(sys_sched_get_priority_min)  /* 160 */
           .long SYMBOL_NAME(sys_sched_rr_get_interval)
           .long SYMBOL_NAME(sys_nanosleep)
           .long SYMBOL_NAME(sys_mremap)
           .long SYMBOL_NAME(sys_setresuid16)
           .long SYMBOL_NAME(sys_getresuid16)      /* 165 */
           .long SYMBOL_NAME(sys_vm86)
           .long SYMBOL_NAME(sys_query_module)
           .long SYMBOL_NAME(sys_poll)
           .long SYMBOL_NAME(sys_nfsservctl)
           .long SYMBOL_NAME(sys_setresgid16)      /* 170 */
           .long SYMBOL_NAME(sys_getresgid16)
           .long SYMBOL_NAME(sys_prctl)
           .long SYMBOL_NAME(sys_rt_sigreturn)
           .long SYMBOL_NAME(sys_rt_sigaction)
           .long SYMBOL_NAME(sys_rt_sigprocmask)   /* 175 */
           .long SYMBOL_NAME(sys_rt_sigpending)
           .long SYMBOL_NAME(sys_rt_sigtimedwait)
           .long SYMBOL_NAME(sys_rt_sigqueueinfo)
           .long SYMBOL_NAME(sys_rt_sigsuspend)
           .long SYMBOL_NAME(sys_pread)            /* 180 */
           .long SYMBOL_NAME(sys_pwrite)
           .long SYMBOL_NAME(sys_chown16)
           .long SYMBOL_NAME(sys_getcwd)
           .long SYMBOL_NAME(sys_capget)
           .long SYMBOL_NAME(sys_capset)           /* 185 */
           .long SYMBOL_NAME(sys_sigaltstack)
           .long SYMBOL_NAME(sys_sendfile)
           .long SYMBOL_NAME(sys_ni_syscall)               /* streams1 */
           .long SYMBOL_NAME(sys_ni_syscall)               /* streams2 */
           .long SYMBOL_NAME(sys_vfork)            /* 190 */
           .long SYMBOL_NAME(sys_getrlimit)
           .long SYMBOL_NAME(sys_mmap2)
           .long SYMBOL_NAME(sys_truncate64)
           .long SYMBOL_NAME(sys_ftruncate64)
           .long SYMBOL_NAME(sys_stat64)           /* 195 */
           .long SYMBOL_NAME(sys_lstat64)
           .long SYMBOL_NAME(sys_fstat64)
           .long SYMBOL_NAME(sys_lchown)
           .long SYMBOL_NAME(sys_getuid)
           .long SYMBOL_NAME(sys_getgid)           /* 200 */
           .long SYMBOL_NAME(sys_geteuid)
           .long SYMBOL_NAME(sys_getegid)
           .long SYMBOL_NAME(sys_setreuid)
           .long SYMBOL_NAME(sys_setregid)
           .long SYMBOL_NAME(sys_getgroups)        /* 205 */
           .long SYMBOL_NAME(sys_setgroups)
           .long SYMBOL_NAME(sys_fchown)
           .long SYMBOL_NAME(sys_setresuid)
           .long SYMBOL_NAME(sys_getresuid)
           .long SYMBOL_NAME(sys_setresgid)        /* 210 */
           .long SYMBOL_NAME(sys_getresgid)
           .long SYMBOL_NAME(sys_chown)
           .long SYMBOL_NAME(sys_setuid)
           .long SYMBOL_NAME(sys_setgid)
           .long SYMBOL_NAME(sys_setfsuid)         /* 215 */
           .long SYMBOL_NAME(sys_setfsgid)
           .long SYMBOL_NAME(sys_pivot_root)
           .long SYMBOL_NAME(sys_mincore)
           .long SYMBOL_NAME(sys_madvise)
           .long SYMBOL_NAME(sys_getdents64)       /* 220 */
           .long SYMBOL_NAME(sys_fcntl64)
           .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for TUX */
           .long SYMBOL_NAME(sys_ni_syscall)       /* Reserved for Security */
           .long SYMBOL_NAME(sys_gettid)
           .long SYMBOL_NAME(sys_readahead)        /* 225 */
При возникновении IRQ Event вызывается IRQ Handler , и любая задача прерывается , после чего управление возвращается точно в точку прерывания :
 
                 Running Task
                |-----------|          (3)
   NORMAL       |   |       | [break execution] IRQ Handler
   EXECUTION (1)|   |       |     ------------->|---------|
                |  \|/      |     |             |  does   |
    IRQ (2)---->| ..        |----->             |  some   |
                |   |       |<-----             |  work   |
   BACK TO      |   |       |     |             |  ..(4). |
   NORMAL    (6)|  \|/      |     <-------------|_________|
   EXECUTION    |___________|  [return to code]
                                       (5)
                  USER MODE                     KERNEL MODE
 
 
   Специальные прерывания таймера возникают при :
  1. Системных предупреждениях
  2. Вызываются системным шедулятором
Ключевым понятием для современных ОС является понятие "Task" или приложение . Приложения выполняются в режиме многозадачности . Переключение между приложениями происходит автоматически через промежуток времени , называемый "timeslice" , которое обычно равно 10 ms . При этом приложение использует переменную , называемую "state" , которая может быть в 2-х состояниях - READY или BLOCKED. Виртуальная память и сегментация позволяют решить проблемы с размещением приложениий независимо от имеющихся ресурсов . Сегмент - это как-бы образ приложения в памяти. Память разбивается на страницы размером по 4 кб , и процесс загружается в одну или несколько таких страниц . На следующей схеме показано , как процесс размещается в памяти :
                                     |      ..            |
                                     |____________________|
                               ----->|      Page 1        |
                               |     |____________________|
                               |     |      ..            |
    ____________________       |     |____________________|
   |                    |      |---->|      Page 2        |
   |      Segment X     |  ----|     |____________________|
   |                    |      |     |       ..           |
   |____________________|      |     |____________________|
                               |     |       ..           |
                               |     |____________________|
                               |---->|      Page 3        |
                                     |____________________|
                                     |       ..           |
Сегмент разбивается на 3 куска , каждый из которых загружается в отдельную страницу . Пэйджинг имеет иерархическую структуру :
 
                             |         |           |         |
                             |         |   Offset2 |  Value  |
                             |         |        /|\|         |
                     Offset1 |         |-----    | |         |
                         /|\ |         |    |    | |         |
                          |  |         |    |   \|/|         |
                          |  |         |    ------>|         |
                         \|/ |         |           |         |
    Base Paging Address ---->|         |           |         |
                             | ....... |           | ....... |
                             |         |           |         |
 
 
   Linux Startup
 
   Ядро стартует с метки  ''startup_32:''
   |startup_32:
      |start_kernel
         |lock_kernel
         |trap_init
         |init_IRQ
         |sched_init
         |softirq_init
         |time_init
         |console_init
         |#ifdef CONFIG_MODULES
            |init_modules
         |#endif
         |kmem_cache_init
         |sti
         |calibrate_delay
         |mem_init
         |kmem_cache_sizes_init
         |pgtable_cache_init
         |fork_init
         |proc_caches_init
         |vfs_caches_init
         |buffer_init
         |page_cache_init
         |signals_init
         |#ifdef CONFIG_PROC_FS
           |proc_root_init
         |#endif
         |#if defined(CONFIG_SYSVIPC)
            |ipc_init
         |#endif
         |check_bugs
         |smp_init
         |rest_init
            |kernel_thread
            |unlock_kernel
            |cpu_idle
   ·  startup_32 [arch/i386/kernel/head.S]
   ·  start_kernel [init/main.c]
   ·  lock_kernel [include/asm/smplock.h]
   ·  trap_init [arch/i386/kernel/traps.c]
   ·  init_IRQ [arch/i386/kernel/i8259.c]
   ·  sched_init [kernel/sched.c]
   ·  softirq_init [kernel/softirq.c]
   ·  time_init [arch/i386/kernel/time.c]
   ·  console_init [drivers/char/tty_io.c]
   ·  init_modules [kernel/module.c]
   ·  kmem_cache_init [mm/slab.c]
   ·  sti [include/asm/system.h]
   ·  calibrate_delay [init/main.c]
   ·  mem_init [arch/i386/mm/init.c]
   ·  kmem_cache_sizes_init [mm/slab.c]
   ·  pgtable_cache_init [arch/i386/mm/init.c]
   ·  fork_init [kernel/fork.c]
   ·  proc_caches_init
   ·  vfs_caches_init [fs/dcache.c]
   ·  buffer_init [fs/buffer.c]
   ·  page_cache_init [mm/filemap.c]
   ·  signals_init [kernel/signal.c]
   ·  proc_root_init [fs/proc/root.c]
   ·  ipc_init [ipc/util.c]
   ·  check_bugs [include/asm/bugs.h]
   ·  smp_init [init/main.c]
   ·  rest_init
   ·  kernel_thread [arch/i386/kernel/process.c]
   ·  unlock_kernel [include/asm/smplock.h]
   ·  cpu_idle [arch/i386/kernel/process.c]
   Фактически функция start_kernel никогда не кончается
   Функция ''init'' :
   |init
      |lock_kernel
      |do_basic_setup
         |mtrr_init
         |sysctl_init
         |pci_init
         |sock_init
         |start_context_thread
         |do_init_calls
            |(*call())-> kswapd_init
      |prepare_namespace
      |free_initmem
      |unlock_kernel
      |execve
 
 
  В линуксе 4 типа сегментов :
   1. Kernel Code [0x10]
   2. Kernel Data / Stack [0x18]
   3. User Code [0x23]
   4. User Data / Stack [0x2b]
 Сегментные регистры :
   ·  CS - Code Segment
   ·  DS - Data Segment
   ·  SS - Stack Segment
   ·  ES - Alternative Segment
Под линуксом возможны 3 уровня пэйджинга , в зависимости от архитектуры . На интеловской платформе 2 уровня пэйджинга . В линуксе память процесса , несмотря на адресную "разбросанность" страниц , его составляющих , в дефрагментации не нуждается . Существует проблема со стеком ядра . Каждый процесс внутри ядра использует общий для всех стек ядра. И размер этого стека в каждой задаче должен быть ограничен . Функции ядра не могут быть рекурсивны и вызываются фиксированное число раз . При вызове IRQ происходит переключение задач . Некоторые процессы , такие например , которые отвечают за TCP/IP , могут в этот момент выстраиваться шедулятором в очередь . Этот механизм в ядре 2.4 называется 'ksoftirqd_CPUn' , где n - это константа kernel_thread. Схема механизма Softirq :
   |cpu_raise_softirq
      |__cpu_raise_softirq
      |wakeup_softirqd
         |wake_up_process
 
   ·  cpu_raise_softirq [kernel/softirq.c]
   ·  __cpu_raise_softirq [include/linux/interrupt.h]
   ·  wakeup_softirq [kernel/softirq.c]
   ·  wake_up_process [kernel/sched.c]
При вызове треда ядра под названием 'ksoftirqd_CPU0'' будет построена и выполнена очередность :
   for (;;) {
      if (!softirq_pending(cpu))
         schedule();
         __set_current_state(TASK_RUNNING);
      while (softirq_pending(cpu)) {
         do_softirq();
         if (current->need_resched)
            schedule
      }
      __set_current_state(TASK_INTERRUPTIBLE)
   }
   ·  ksoftirqd [kernel/softirq.c]
Kernel Threads
В монолитном линукс-ядре нужно выделить несколько ''kernel threads''. Они используюи KERNEL-память и у них 0-я привилегия . Они создаются функцией ''kernel_thread [arch/i386/kernel/process]''
   int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
   {
           long retval, d0;
           __asm__ __volatile__(
 "movl %%esp,%%esi\n\t"
 "int $0x80\n\t"         /* Linux/i386 system call */
 "cmpl %%esp,%%esi\n\t"  /* child or parent? */
 "je 1f\n\t"             /* parent - jump */
 /* Load the argument into eax, and push it.  That way, it does
 * not matter whether the called function is compiled with
 * -mregparm or not.  */
 "movl %4,%%eax\n\t"
 "pushl %%eax\n\t"
 "call *%5\n\t"          /* call fn */
 "movl %3,%0\n\t"        /* exit */
 "int $0x80\n"
 "1:\t"
 :"=&a" (retval), "=&S" (d0)
 :"0" (__NR_clone), "i" (__NR_exit),
 "r" (arg), "r" (fn),
 "b" (flags | CLONE_VM)
                   : "memory");
           return retval;
   }
Т.о. сгенерированная задача будет ожидать критичное по скорости выполнения событие типа свопа или usb-шное событие . Ниже приведен список наиболее важных kernel threads (''ps x''):
   PID      COMMAND
    1        init
    2        keventd
    3        kswapd
    4        kreclaimd
    5        bdflush
    6        kupdated
    7        kacpid
   67        khubd
Они , в свою очередь , могут вызывать другие пользовательские задачи (из /etc/inittab) типа консольных демонов , tty-демонов,сетевых демонов (скрипт ''rc'' ).

Пример Kernel Threads: kswapd [mm/vmscan.c].
 Процедуры инициализации :
   |do_initcalls
      |kswapd_init
         |kernel_thread
            |syscall fork (in assembler)
   do_initcalls [init/main.c]
   kswapd_init [mm/vmscan.c]
   kernel_thread [arch/i386/kernel/process.c]
Kernel Modules
Linux Kernel modules - это код (например: fs, net, hw - драйвера) , выполняющийся в пространстве ядра , который подключается после загрузки , по команде пользователя . Такие вещи , как шедулятор , управление прерываниями или сетевое ядро , не может быть загружено из модулей , поэтому оно жестко вкомпилировано в ядро . Модули , инсталлированные в вашей системе , можно найти в "/lib/modules/KERNEL_VERSION/" Для загрузки модуля , наберите команду :
 	  insmod MODULE_NAME parameters
       пример: insmod ne io=0x300 irq=9
Для загрузки можно использовать другую команду - modprobe , которая сама отыщет нужные параметры ,
 например в  /etc/conf.modules.
 Для выгрузки модуля :
 	   rmmod MODULE_NAME
  Модуль всегда включает в себя
    1. Функцию "init_module"
    2. Функцию "cleanup_module"
 Если таких функций в модуле нет , 
 тогда там должны быть по крайней мере 2 макроса :
 	  1. module_init(FUNCTION_NAME)
 	  2. module_exit(FUNCTION_NAME)
 Модуль видит переменную ядра с помощь макроса  EXPORT_SYMBOL.
  При разработке модулей нужно иметь в виду следующее : на стороне ядра мы имеем :
 	  void (*foo_function_pointer)(void *);
 	  if (foo_function_pointer)
     	(foo_function_pointer)(parameter);
   // на стороне модуля
   extern void (*foo_function_pointer)(void *);
   void my_function(void *parameter) {    //My code  }
   int init_module()
   {
     foo_function_pointer = &my_function;
   }
   int cleanup_module()
   {
     foo_function_pointer = NULL;
   }
Каталог /proc .
/proc - каталог , который позволяет напрямую "общаться" с ядром . Линукс использует его для поддержки т.н. direct kernel communications: можно например посмотреть основные структуры процессов , изменить максимальное число трэдов , отдебажить состояние шины данных типа ISA или PCI , узнать о том , какие карты проинсталированы и какие им назначены порты и прерывания .
   |-- bus
   |   |-- pci
   |   |   |-- 00
   |   |   |   |-- 00.0
   |   |   |   |-- 01.0
   |   |   |   |-- 07.0
   |   |   |   |-- 07.1
   |   |   |   |-- 07.2
   |   |   |   |-- 07.3
   |   |   |   |-- 07.4
   |   |   |   |-- 07.5
   |   |   |   |-- 09.0
   |   |   |   |-- 0a.0
   |   |   |   `-- 0f.0
   |   |   |-- 01
   |   |   |   `-- 00.0
   |   |   `-- devices
   |   `-- usb
   |-- cmdline
   |-- cpuinfo
   |-- devices
   |-- dma
   |-- dri
   |   `-- 0
   |       |-- bufs
   |       |-- clients
   |       |-- mem
   |       |-- name
   |       |-- queues
   |       |-- vm
   |       `-- vma
   |-- driver
   |-- execdomains
   |-- filesystems
   |-- fs
   |-- ide
   |   |-- drivers
   |   |-- hda -> ide0/hda
   |   |-- hdc -> ide1/hdc
   |   |-- ide0
   |   |   |-- channel
   |   |   |-- config
   |   |   |-- hda
   |   |   |   |-- cache
   |   |   |   |-- capacity
   |   |   |   |-- driver
   |   |   |   |-- geometry
   |   |   |   |-- identify
   |   |   |   |-- media
   |   |   |   |-- model
   |   |   |   |-- settings
   |   |   |   |-- smart_thresholds
   |   |   |   `-- smart_values
   |   |   |-- mate
   |   |   `-- model
   |   |-- ide1
   |   |   |-- channel
   |   |   |-- config
   |   |   |-- hdc
   |   |   |   |-- capacity
   |   |   |   |-- driver
   |   |   |   |-- identify
   |   |   |   |-- media
   |   |   |   |-- model
   |   |   |   `-- settings
   |   |   |-- mate
   |   |   `-- model
   |   `-- via
   |-- interrupts
   |-- iomem
   |-- ioports
   |-- irq
   |   |-- 0
   |   |-- 1
   |   |-- 10
   |   |-- 11
   |   |-- 12
   |   |-- 13
   |   |-- 14
   |   |-- 15
   |   |-- 2
   |   |-- 3
   |   |-- 4
   |   |-- 5
   |   |-- 6
   |   |-- 7
   |   |-- 8
   |   |-- 9
   |   `-- prof_cpu_mask
   |-- kcore
   |-- kmsg
   |-- ksyms
   |-- loadavg
   |-- locks
   |-- meminfo
   |-- misc
   |-- modules
   |-- mounts
   |-- mtrr
   |-- net
   |   |-- arp
   |   |-- dev
   |   |-- dev_mcast
   |   |-- ip_fwchains
   |   |-- ip_fwnames
   |   |-- ip_masquerade
   |   |-- netlink
   |   |-- netstat
   |   |-- packet
   |   |-- psched
   |   |-- raw
   |   |-- route
   |   |-- rt_acct
   |   |-- rt_cache
   |   |-- rt_cache_stat
   |   |-- snmp
   |   |-- sockstat
   |   |-- softnet_stat
   |   |-- tcp
   |   |-- udp
   |   |-- unix
   |   `-- wireless
   |-- partitions
   |-- pci
   |-- scsi
   |   |-- ide-scsi
   |   |   `-- 0
   |   `-- scsi
   |-- self -> 2069
   |-- slabinfo
   |-- stat
   |-- swaps
   |-- sys
   |   |-- abi
   |   |   |-- defhandler_coff
   |   |   |-- defhandler_elf
   |   |   |-- defhandler_lcall7
   |   |   |-- defhandler_libcso
   |   |   |-- fake_utsname
   |   |   `-- trace
   |   |-- debug
   |   |-- dev
   |   |   |-- cdrom
   |   |   |   |-- autoclose
   |   |   |   |-- autoeject
   |   |   |   |-- check_media
   |   |   |   |-- debug
   |   |   |   |-- info
   |   |   |   `-- lock
   |   |   `-- parport
   |   |       |-- default
   |   |       |   |-- spintime
   |   |       |   `-- timeslice
   |   |       `-- parport0
   |   |           |-- autoprobe
   |   |           |-- autoprobe0
   |   |           |-- autoprobe1
   |   |           |-- autoprobe2
   |   |           |-- autoprobe3
   |   |           |-- base-addr
   |   |           |-- devices
   |   |           |   |-- active
   |   |           |   `-- lp
   |   |           |       `-- timeslice
   |   |           |-- dma
   |   |           |-- irq
   |   |           |-- modes
   |   |           `-- spintime
   |   |-- fs
   |   |   |-- binfmt_misc
   |   |   |-- dentry-state
   |   |   |-- dir-notify-enable
   |   |   |-- dquot-nr
   |   |   |-- file-max
   |   |   |-- file-nr
   |   |   |-- inode-nr
   |   |   |-- inode-state
   |   |   |-- jbd-debug
   |   |   |-- lease-break-time
   |   |   |-- leases-enable
   |   |   |-- overflowgid
   |   |   `-- overflowuid
   |   |-- kernel
   |   |   |-- acct
   |   |   |-- cad_pid
   |   |   |-- cap-bound
   |   |   |-- core_uses_pid
   |   |   |-- ctrl-alt-del
   |   |   |-- domainname
   |   |   |-- hostname
   |   |   |-- modprobe
   |   |   |-- msgmax
   |   |   |-- msgmnb
   |   |   |-- msgmni
   |   |   |-- osrelease
   |   |   |-- ostype
   |   |   |-- overflowgid
   |   |   |-- overflowuid
   |   |   |-- panic
   |   |   |-- printk
   |   |   |-- random
   |   |   |   |-- boot_id
   |   |   |   |-- entropy_avail
   |   |   |   |-- poolsize
   |   |   |   |-- read_wakeup_threshold
   |   |   |   |-- uuid
   |   |   |   `-- write_wakeup_threshold
   |   |   |-- rtsig-max
   |   |   |-- rtsig-nr
   |   |   |-- sem
   |   |   |-- shmall
   |   |   |-- shmmax
   |   |   |-- shmmni
   |   |   |-- sysrq
   |   |   |-- tainted
   |   |   |-- threads-max
   |   |   `-- version
   |   |-- net
   |   |   |-- 802
   |   |   |-- core
   |   |   |   |-- hot_list_length
   |   |   |   |-- lo_cong
   |   |   |   |-- message_burst
   |   |   |   |-- message_cost
   |   |   |   |-- mod_cong
   |   |   |   |-- netdev_max_backlog
   |   |   |   |-- no_cong
   |   |   |   |-- no_cong_thresh
   |   |   |   |-- optmem_max
   |   |   |   |-- rmem_default
   |   |   |   |-- rmem_max
   |   |   |   |-- wmem_default
   |   |   |   `-- wmem_max
   |   |   |-- ethernet
   |   |   |-- ipv4
   |   |   |   |-- conf
   |   |   |   |   |-- all
   |   |   |   |   |   |-- accept_redirects
   |   |   |   |   |   |-- accept_source_route
   |   |   |   |   |   |-- arp_filter
   |   |   |   |   |   |-- bootp_relay
   |   |   |   |   |   |-- forwarding
   |   |   |   |   |   |-- log_martians
   |   |   |   |   |   |-- mc_forwarding
   |   |   |   |   |   |-- proxy_arp
   |   |   |   |   |   |-- rp_filter
   |   |   |   |   |   |-- secure_redirects
   |   |   |   |   |   |-- send_redirects
   |   |   |   |   |   |-- shared_media
   |   |   |   |   |   `-- tag
   |   |   |   |   |-- default
   |   |   |   |   |   |-- accept_redirects
   |   |   |   |   |   |-- accept_source_route
   |   |   |   |   |   |-- arp_filter
   |   |   |   |   |   |-- bootp_relay
   |   |   |   |   |   |-- forwarding
   |   |   |   |   |   |-- log_martians
   |   |   |   |   |   |-- mc_forwarding
   |   |   |   |   |   |-- proxy_arp
   |   |   |   |   |   |-- rp_filter
   |   |   |   |   |   |-- secure_redirects
   |   |   |   |   |   |-- send_redirects
   |   |   |   |   |   |-- shared_media
   |   |   |   |   |   `-- tag
   |   |   |   |   |-- eth0
   |   |   |   |   |   |-- accept_redirects
   |   |   |   |   |   |-- accept_source_route
   |   |   |   |   |   |-- arp_filter
   |   |   |   |   |   |-- bootp_relay
   |   |   |   |   |   |-- forwarding
   |   |   |   |   |   |-- log_martians
   |   |   |   |   |   |-- mc_forwarding
   |   |   |   |   |   |-- proxy_arp
   |   |   |   |   |   |-- rp_filter
   |   |   |   |   |   |-- secure_redirects
   |   |   |   |   |   |-- send_redirects
   |   |   |   |   |   |-- shared_media
   |   |   |   |   |   `-- tag
   |   |   |   |   |-- eth1
   |   |   |   |   |   |-- accept_redirects
   |   |   |   |   |   |-- accept_source_route
   |   |   |   |   |   |-- arp_filter
   |   |   |   |   |   |-- bootp_relay
   |   |   |   |   |   |-- forwarding
   |   |   |   |   |   |-- log_martians
   |   |   |   |   |   |-- mc_forwarding
   |   |   |   |   |   |-- proxy_arp
   |   |   |   |   |   |-- rp_filter
   |   |   |   |   |   |-- secure_redirects
   |   |   |   |   |   |-- send_redirects
   |   |   |   |   |   |-- shared_media
   |   |   |   |   |   `-- tag
   |   |   |   |   `-- lo
   |   |   |   |       |-- accept_redirects
   |   |   |   |       |-- accept_source_route
   |   |   |   |       |-- arp_filter
   |   |   |   |       |-- bootp_relay
   |   |   |   |       |-- forwarding
   |   |   |   |       |-- log_martians
   |   |   |   |       |-- mc_forwarding
   |   |   |   |       |-- proxy_arp
   |   |   |   |       |-- rp_filter
   |   |   |   |       |-- secure_redirects
   |   |   |   |       |-- send_redirects
   |   |   |   |       |-- shared_media
   |   |   |   |       `-- tag
   |   |   |   |-- icmp_echo_ignore_all
   |   |   |   |-- icmp_echo_ignore_broadcasts
   |   |   |   |-- icmp_ignore_bogus_error_responses
   |   |   |   |-- icmp_ratelimit
   |   |   |   |-- icmp_ratemask
   |   |   |   |-- inet_peer_gc_maxtime
   |   |   |   |-- inet_peer_gc_mintime
   |   |   |   |-- inet_peer_maxttl
   |   |   |   |-- inet_peer_minttl
   |   |   |   |-- inet_peer_threshold
   |   |   |   |-- ip_autoconfig
   |   |   |   |-- ip_conntrack_max
   |   |   |   |-- ip_default_ttl
   |   |   |   |-- ip_dynaddr
   |   |   |   |-- ip_forward
   |   |   |   |-- ip_local_port_range
   |   |   |   |-- ip_no_pmtu_disc
   |   |   |   |-- ip_nonlocal_bind
   |   |   |   |-- ipfrag_high_thresh
   |   |   |   |-- ipfrag_low_thresh
   |   |   |   |-- ipfrag_time
   |   |   |   |-- neigh
   |   |   |   |   |-- default
   |   |   |   |   |   |-- anycast_delay
   |   |   |   |   |   |-- app_solicit
   |   |   |   |   |   |-- base_reachable_time
   |   |   |   |   |   |-- delay_first_probe_time
   |   |   |   |   |   |-- gc_interval
   |   |   |   |   |   |-- gc_stale_time
   |   |   |   |   |   |-- gc_thresh1
   |   |   |   |   |   |-- gc_thresh2
   |   |   |   |   |   |-- gc_thresh3
   |   |   |   |   |   |-- locktime
   |   |   |   |   |   |-- mcast_solicit
   |   |   |   |   |   |-- proxy_delay
   |   |   |   |   |   |-- proxy_qlen
   |   |   |   |   |   |-- retrans_time
   |   |   |   |   |   |-- ucast_solicit
   |   |   |   |   |   `-- unres_qlen
   |   |   |   |   |-- eth0
   |   |   |   |   |   |-- anycast_delay
   |   |   |   |   |   |-- app_solicit
   |   |   |   |   |   |-- base_reachable_time
   |   |   |   |   |   |-- delay_first_probe_time
   |   |   |   |   |   |-- gc_stale_time
   |   |   |   |   |   |-- locktime
   |   |   |   |   |   |-- mcast_solicit
   |   |   |   |   |   |-- proxy_delay
   |   |   |   |   |   |-- proxy_qlen
   |   |   |   |   |   |-- retrans_time
   |   |   |   |   |   |-- ucast_solicit
   |   |   |   |   |   `-- unres_qlen
   |   |   |   |   |-- eth1
   |   |   |   |   |   |-- anycast_delay
   |   |   |   |   |   |-- app_solicit
   |   |   |   |   |   |-- base_reachable_time
   |   |   |   |   |   |-- delay_first_probe_time
   |   |   |   |   |   |-- gc_stale_time
   |   |   |   |   |   |-- locktime
   |   |   |   |   |   |-- mcast_solicit
   |   |   |   |   |   |-- proxy_delay
   |   |   |   |   |   |-- proxy_qlen
   |   |   |   |   |   |-- retrans_time
   |   |   |   |   |   |-- ucast_solicit
   |   |   |   |   |   `-- unres_qlen
   |   |   |   |   `-- lo
   |   |   |   |       |-- anycast_delay
   |   |   |   |       |-- app_solicit
   |   |   |   |       |-- base_reachable_time
   |   |   |   |       |-- delay_first_probe_time
   |   |   |   |       |-- gc_stale_time
   |   |   |   |       |-- locktime
   |   |   |   |       |-- mcast_solicit
   |   |   |   |       |-- proxy_delay
   |   |   |   |       |-- proxy_qlen
   |   |   |   |       |-- retrans_time
   |   |   |   |       |-- ucast_solicit
   |   |   |   |       `-- unres_qlen
   |   |   |   |-- route
   |   |   |   |   |-- error_burst
   |   |   |   |   |-- error_cost
   |   |   |   |   |-- flush
   |   |   |   |   |-- gc_elasticity
   |   |   |   |   |-- gc_interval
   |   |   |   |   |-- gc_min_interval
   |   |   |   |   |-- gc_thresh
   |   |   |   |   |-- gc_timeout
   |   |   |   |   |-- max_delay
   |   |   |   |   |-- max_size
   |   |   |   |   |-- min_adv_mss
   |   |   |   |   |-- min_delay
   |   |   |   |   |-- min_pmtu
   |   |   |   |   |-- mtu_expires
   |   |   |   |   |-- redirect_load
   |   |   |   |   |-- redirect_number
   |   |   |   |   `-- redirect_silence
   |   |   |   |-- tcp_abort_on_overflow
   |   |   |   |-- tcp_adv_win_scale
   |   |   |   |-- tcp_app_win
   |   |   |   |-- tcp_dsack
   |   |   |   |-- tcp_ecn
   |   |   |   |-- tcp_fack
   |   |   |   |-- tcp_fin_timeout
   |   |   |   |-- tcp_keepalive_intvl
   |   |   |   |-- tcp_keepalive_probes
   |   |   |   |-- tcp_keepalive_time
   |   |   |   |-- tcp_max_orphans
   |   |   |   |-- tcp_max_syn_backlog
   |   |   |   |-- tcp_max_tw_buckets
   |   |   |   |-- tcp_mem
   |   |   |   |-- tcp_orphan_retries
   |   |   |   |-- tcp_reordering
   |   |   |   |-- tcp_retrans_collapse
   |   |   |   |-- tcp_retries1
   |   |   |   |-- tcp_retries2
   |   |   |   |-- tcp_rfc1337
   |   |   |   |-- tcp_rmem
   |   |   |   |-- tcp_sack
   |   |   |   |-- tcp_stdurg
   |   |   |   |-- tcp_syn_retries
   |   |   |   |-- tcp_synack_retries
   |   |   |   |-- tcp_syncookies
   |   |   |   |-- tcp_timestamps
   |   |   |   |-- tcp_tw_recycle
   |   |   |   |-- tcp_window_scaling
   |   |   |   `-- tcp_wmem
   |   |   `-- unix
   |   |       `-- max_dgram_qlen
   |   |-- proc
   |   `-- vm
   |       |-- bdflush
   |       |-- kswapd
   |       |-- max-readahead
   |       |-- min-readahead
   |       |-- overcommit_memory
   |       |-- page-cluster
   |       `-- pagetable_cache
   |-- sysvipc
   |   |-- msg
   |   |-- sem
   |   `-- shm
   |-- tty
   |   |-- driver
   |   |   `-- serial
   |   |-- drivers
   |   |-- ldisc
   |   `-- ldiscs
   |-- uptime
   `-- version  
При этом можно не только получить информацию о переменных ядра , но и модифицировать некоторые из них - см. /proc/sys каталог :
   /proc/sys/
             acpi
             dev
             debug
             fs
             proc
             net
             vm
             kernel
Ниже перечислены некоторые значения каталога /proc/sys/kernel для модификации :
   overflowgid
   overflowuid
   random
   threads-max // Max number of threads, typically 16384
   sysrq // kernel hack: you can view istant register values and more
   sem
   msgmnb
   msgmni
   msgmax
   shmmni
   shmall
   shmmax
   rtsig-max
   rtsig-nr
   modprobe // modprobe file location
   printk
   ctrl-alt-del
   cap-bound
   panic
   domainname // domain name of your Linux box
   hostname // host name of your Linux box
   version // date info about kernel compilation
   osrelease // kernel version (i.e. 2.4.5)
   ostype // Linux!
/proc/sys/net Этот каталог позволяет изменить сетевые настройки ядра :
   core
   ipv4
   ipv6
   unix
   ethernet
   802
/proc/sys/net/core Ниже идет перечисление таких сетевых параметров , как "netdev_max_backlog" (300), длина пакета. Это может изменить производительность ваше системы по получению пакетов.
     300    *        100             =     30 000
   packets     HZ(Timeslice freq)         packets/s
   30 000   *       1000             =      30 M
   packets     average (Bytes/packet)   throughput Bytes/s
Если вы хотите увеличить производительность , вам нужно увеличить netdev_max_backlog,:
 	  echo 4000 > /proc/sys/net/core/netdev_max_backlog
   /proc/sys/net/ipv4
   "ip_forward" - разрешает или запрещает ip forwarding .
   /proc/sys/net/ipv4/conf/interface
 Позволяет поддерживать wireless networks
 "proxy_arp" - arp feature.
 "send_redirects" - посылка ICMP_REDIRECT
Multitasking Выполняемый процесс может быть в одном из следующих состояний : [include/linux.h]):
   1. TASK_RUNNING
   2. TASK_INTERRUPTIBLE - в ожидании прерывания
   3. TASK_UNINTERRUPTIBLE - в очереди
   4. TASK_ZOMBIE - процесс , потерявшиий родителя
   5. TASK_STOPPED - процесс под дебагом
 
   Graphical Interaction
          ______________     CPU Available     ______________
         |              |  ---------------->  |              |
         | TASK_RUNNING |                     | Real Running |
         |______________|  <----------------  |______________|
                              CPU Busy
               |   /|\
   Waiting for |    | Resource
    Resource   |    | Available
              \|/   |
       ______________________
      |                      |
      | TASK_INTERRUPTIBLE / |
      | TASK-UNINTERRUPTIBLE |
      |______________________|
Timeslice
Каждые 10 ms генерится IRQ0 comes, которое играет ведущую роль в многозадачности. Этот сигнал приходит от PIC 8259 :
       _____         ______        ______
      | CPU |<------| 8259 |------| 8253 |
      |_____| IRQ0  |______|      |___/|\|
                                       |_____ CLK 1.193.180 MHz
 
   // From include/asm/param.h
   #ifndef HZ
   #define HZ 100
   #endif
 
   // From include/asm/timex.h
   #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
 
   // From include/linux/timex.h
   #define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
 
   // From arch/i386/kernel/i8259.c
   outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
   outb_p(LATCH & 0xff , 0x40); /* LSB */
   outb(LATCH >> 8 , 0x40); /* MSB */
PIT,или Programmable Interval Timer , запрограммирован с LATCH = (1193180/HZ) = 11931.8 . LATCH = 11931.8 дает на выходе 8253 частоту 1193180 / 11931.8 = 100 Hz, поэтому период = 10ms. Это частота с которой шедулятор моет "перебирать" процессы , стоящие в очереди .

Linux Timer IRQ ICA
   Linux Timer IRQ
   IRQ 0 [Timer]
    |
   \|/
   |IRQ0x00_interrupt        //   wrapper IRQ handler
      |SAVE_ALL              ---
         |do_IRQ                |   wrapper routines
            |handle_IRQ_event  ---
               |handler() -> timer_interrupt
                  |do_timer_interrupt
                     |do_timer
                        |jiffies++;
                        |update_process_times
                        |if (--counter <= 0) { 
                           |counter = 0;       
                           |need_resched = 1;  
                        |}
            |do_softirq
            |while (need_resched) { // if necessary
               |schedule             //   reschedule
               |handle_softirq
            |}
      |RESTORE_ALL
   ·  IRQ0x00_interrupt, SAVE_ALL [include/asm/hw_irq.h]
   ·  do_IRQ, handle_IRQ_event [arch/i386/kernel/irq.c]
 timer_interrupt, do_timer_interrupt [arch/i386/kernel/time.c]
   ·  do_timer, update_process_times [kernel/timer.c]
   ·  do_softirq [kernel/soft_irq.c]
  RESTORE_ALL, while loop [arch/i386/kernel/entry.S]
У каждой задачи есть счетчик , и когда он уменьшается до нуля , автоматически происходит переключение на другую задачу .
     Scheduler
scheduler - это код , который выбирает , какая задача будет выполняться в данный момент .
   |schedule
      |do_softirq // manages post-IRQ work
      |for each task
         |calculate counter
      |prepare_to__switch // does anything
      |switch_mm // change Memory context (change CR3 value)
      |switch_to (assembler)
         |SAVE ESP
         |RESTORE future_ESP
         |SAVE EIP
         |push future_EIP *** push parameter as we did a call
            |jmp __switch_to (it does some TSS work)
            |__switch_to()
             ..
 |ret *** ret from call using future_EIP in place of call address
         new_task
Когда приходит прерывание от устройства, линукс выполняет переключение на задачу , которая начинает опрашивать это устройство . Для того , этот опрос не пожирал все ресурсы , начиная с версии 1.0 реализован механизм "bottom half" (BH). В более поздних версиях bh заменен на более динамичную очередь .
  Схема работы BH :
   1. Декларирование
   2. Маркировка
   3. Выполнение
 
 	Декларация:
   #define DECLARE_TASK_QUEUE(q) LIST_HEAD(q)
   #define LIST_HEAD(name) \
      struct list_head name = LIST_HEAD_INIT(name)
   struct list_head {
      struct list_head *next, *prev;
   };
   #define LIST_HEAD_INIT(name) { &(name), &(name) }
   ''DECLARE_TASK_QUEUE'' [include/linux/tqueue.h, include/linux/list.h]
"DECLARE_TASK_QUEUE(q)" - это макрос для декларирования структуры "q" , управляющей очередью заданий .
Маркировка
 Функция "mark_bh" [include/linux/interrupt.h]
   |mark_bh(NUMBER)
      |tasklet_hi_schedule(bh_task_vec + NUMBER)
         |insert into tasklet_hi_vec
            |__cpu_raise_softirq(HI_SOFTIRQ)
               |soft_active |= (1 << HI_SOFTIRQ)
                   ''mark_bh''[include/linux/interrupt.h]
Выполнение - функция "do_IRQ" [arch/i386/kernel/irq.c]
   |do_softirq
 |h->action(h)-> softirq_vec[TASKLET_SOFTIRQ]->action -> tasklet_action
         |tasklet_vec[0].list->func
  Список низко-уровневых подпрограмм :
   set_intr_gate
   set_trap_gate
   set_task_gate (not used).
 (*interrupt)[NR_IRQS](void) = { IRQ0x00_interrupt, IRQ0x01_interrupt,  ..}
Переключение задач Оно происходит в следующих случаях :
   ·  TimeSlice
      когда приложение начинает опрашивать какой-то ресурс , 
      оно засыпает
      когда процесс в ожидании пайпа от другого процесса , 
      нужно переключиться на этот другой процесс
 #define switch_to(prev,next,last) do {                            \
         asm volatile("pushl %%esi\n\t"                             \
                 "pushl %%edi\n\t"                                  \
                 "pushl %%ebp\n\t"                                  \
                 "movl %%esp,%0\n\t"        /* save ESP */          \
                 "movl %3,%%esp\n\t"        /* restore ESP */       \
                 "movl $1f,%1\n\t"          /* save EIP */          \
                 "pushl %4\n\t"             /* restore EIP */       \
                 "jmp __switch_to\n"                                \
                 "1:\t"                                             \
                 "popl %%ebp\n\t"                                   \
                 "popl %%edi\n\t"                                   \
                 "popl %%esi\n\t"                                   \
                 :"=m" (prev->thread.esp),"=m" (prev->thread.eip),  \
                         "=b" (last)                                \
                 :"m" (next->thread.esp),"m" (next->thread.eip),    \
                         "a" (prev), "d" (next),                    \
                         "b" (prev));                               \
   } while (0)
  Переключение происходит после метки 1 :
         U S E R   M O D E                 K E R N E L     M O D E
    |          |     |          |       |          |     |          |
    |          |     |          | Timer |          |     |          |
    |          |     |  Normal  |  IRQ  |          |     |          |
    |          |     |   Exec   |------>|Timer_Int.|     |          |
    |          |     |     |    |       | ..       |     |          |
    |          |     |    \|/   |       |schedule()|     | Task1 Ret|
    |          |     |          |       |_switch_to|<--  |  Address |
    |__________|     |__________|       |          |  |  |          |
                                        |          |  |S |          |
   Task1 Data/Stack   Task1 Code        |          |  |w |          |
                                        |          | T|i |          |
                                        |          | a|t |          |
    |          |     |          |       |          | s|c |          |
    |          |     |          | Timer |          | k|h |          |
    |          |     |  Normal  |  IRQ  |          |  |i |          |
    |          |     |   Exec   |------>|Timer_Int.|  |n |          |
    |          |     |     |    |       | ..       |  |g |          |
    |          |     |    \|/   |       |schedule()|  |  | Task2 Ret|
    |          |     |          |       |_switch_to|<--  |  Address |
    |__________|     |__________|       |__________|     |__________|
 
   Task2 Data/Stack   Task2 Code        Kernel Code  Kernel Data/Stack
. Fork
Fork - генерация нового процесса . Имеется родительский процесс , структуры данных которого используются для наследуемого процесса
                                  |         |
                                  | ..      |
            Task Parent           |         |
            |         |           |         |
            |  fork   |---------->|  CREATE |
            |         |          /|   NEW   |
            |_________|         / |   TASK  |
                               /  |         |
                ---           /   |         |
                ---          /    | ..      |
                            /     |         |
            Task Child     /
            |         |   /
            |  fork   |<-/
            |         |
            |_________|
Порождаемый процес отличается от родителя следующим :
1 PID
2. child-процесс возвращает 0, в то время как родительский вернет PID
3. память child-процесса помечена как ''READ + EXECUTE'', не "WRITE''
   Fork ICA
   |sys_fork
      |do_fork
         |alloc_task_struct
            |__get_free_pages
          |p->state = TASK_UNINTERRUPTIBLE
          |copy_flags
          |p->pid = get_pid
          |copy_files
          |copy_fs
          |copy_sighand
          |copy_mm // should manage CopyOnWrite (I part)
             |allocate_mm
             |mm_init
                |pgd_alloc -> get_pgd_fast
                   |get_pgd_slow
             |dup_mmap
                |copy_page_range
                   |ptep_set_wrprotect
                      |clear_bit // set page to read-only
             |copy_segments // For LDT
          |copy_thread
             |childregs->eax = 0
             |p->thread.esp = childregs // child fork returns 0
         |p->thread.eip = ret_from_fork // child starts from fork exit
          |retval = p->pid // parent fork returns child pid
          |SET_LINKS // insertion of task into the list pointers
          |nr_threads++ // Global variable
          |wake_up_process(p) // Now we can wake up just created child
          |return retval
 
                  fork ICA
   ·  sys_fork [arch/i386/kernel/process.c]
   ·  do_fork [kernel/fork.c]
   ·  alloc_task_struct [include/asm/processor.c]
   ·  __get_free_pages [mm/page_alloc.c]
   ·  get_pid [kernel/fork.c]
   ·  copy_files
   ·  copy_fs
   ·  copy_sighand
   ·  copy_mm
   ·  allocate_mm
   ·  mm_init
   ·  pgd_alloc -> get_pgd_fast [include/asm/pgalloc.h]
   ·  get_pgd_slow
   ·  dup_mmap [kernel/fork.c]
   ·  copy_page_range [mm/memory.c]
   ·  ptep_set_wrprotect [include/asm/pgtable.h]
   ·  clear_bit [include/asm/bitops.h]
   ·  copy_segments [arch/i386/kernel/process.c]
   ·  copy_thread
   ·  SET_LINKS [include/linux/sched.h]
   ·  wake_up_process [kernel/sched.c]
Copy on Write При попытке записать данные в память child-процесса возникает Page Fault, при этом будет выделена новая страница памяти
    | Page
    | Fault
    | Exception
    -----------> |do_page_fault
                    |handle_mm_fault
                       |handle_pte_fault
                          |do_wp_page
                          |alloc_page      // Allocate a new page
                          |break_cow
                          |copy_cow_page // Copy old page to new one
                          |establish_pte // reconfig Page Table pointers
                                   |set_pte
                 Page Fault ICA
   ·  do_page_fault [arch/i386/mm/fault.c]
   ·  handle_mm_fault [mm/memory.c]
   ·  handle_pte_fault
   ·  do_wp_page
   ·  alloc_page [include/linux/mm.h]
   ·  break_cow [mm/memory.c]
   ·  copy_cow_page
   ·  establish_pte
   ·  set_pte [include/asm/pgtable-3level.h]
Linux Memory Management Linux при управлении памятью использует комбинацию из сегментации + пэйджинга . Linux использует 4 сегмента :
   ·  2 сегмента (код и стек) для KERNEL SPACE
   ·  2 сегмента (код и стек) для USER SPACE 
      4 GB--->|                |    |
              |     Kernel     |    |  Kernel Space (Code + Data/Stack)
              |                |  __|
      3 GB--->|----------------|  __
              |                |    |
              |                |    |
      2 GB--->|                |    |
              |     Tasks      |    |  User Space (Code + Data/Stack)
              |                |    |
      1 GB--->|                |    |
              |                |    |
              |________________|  __|
    0x00000000
 
  Пэйджинг в 386-м линуксе 2-уровневый :
      ------------------------------------------------------------
  L    I    N    E    A    R         A    D    D    R    E    S    S
 ----------------------------------------------------------------
           \___/                 \___/                     \_____/
 
 PD offset              PF offset                 Frame offset
 [10 bits]              [10 bits]                 [12 bits]
         |                     |                          |
         |                     |     -----------          |
         |                     |     |  Value  |----------|---------
         |     |         |     |     |---------|   /|\    |        |
         |     |         |     |     |         |    |     |        |
         |     |         |     |     |         |    | Frame offset |
         |     |         |     |     |         |   \|/             |
         |     |         |     |     |---------|<------            |
         |     |         |     |     |         |      |            |
         |     |         |     |     |         |      | x 4096     |
         |     |         |  PF offset|_________|-------            |
         |     |         |       /|\ |         |                   |
         PD offset |_________|-----   |  |         |          _________|
         /|\ |         |    |   |  |         |          |
         |  |         |    |  \|/ |         |         \|/
 _____       |  |         |    ------>|_________|   PHYSICAL ADDRESS
 |     |     \|/ |         |    x 4096 |         |
 | CR3 |-------->|         |           |         |
 |_____|         | ....... |           | ....... |
                 |         |           |         |
 
                Page Directory          Page File
У различных процессов фактически сегментные адреса будут одинаковые , различаться будет лишь содержимое регистра CR3 . В User mode одновременно может быть запущено не более 768 процессов(768*4MB = 3GB). В Kernel Mode это справедливо для 256 процессов .
               ________________ _____
              |Other KernelData|___  |  |                |
              |----------------|   | |__|                |
              |     Kernel     |\  |____|   Real Other   |
     3 GB --->|----------------| \      |   Kernel Data  |
              |                |\ \     |                |
              |              __|_\_\____|__   Real       |
              |      Tasks     |  \ \   |     Tasks      |
              |              __|___\_\__|__   Space      |
              |                |    \ \ |                |
              |                |     \ \|----------------|
              |                |      \ |Real KernelSpace|
              |________________|       \|________________|
 
           Logical Addresses          Physical Addresses
Работа с памятью начинается при загрузке в kmem_cache_init (launched by start_kernel [init/main.c]
   |kmem_cache_init
      |kmem_cache_estimate
   kmem_cache_init [mm/slab.c]
   kmem_cache_estimate
 
   Далее -  mem_init [init/main.c])
   |mem_init
      |free_all_bootmem
         |free_all_bootmem_core
   mem_init [arch/i386/mm/init.c]
   free_all_bootmem [mm/bootmem.c]
   free_all_bootmem_core
 
   Пример выделения памяти в run-time :
   |copy_mm
      |allocate_mm = kmem_cache_alloc
         |__kmem_cache_alloc
            |kmem_cache_alloc_one
               |alloc_new_slab
                  |kmem_cache_grow
                     |kmem_getpages
                        |__get_free_pages
                           |alloc_pages
                              |alloc_pages_pgdat
                                 |__alloc_pages
                                    |rmqueue
                                    |reclaim_pages
Linux Networking Для каждой разновидности NIC имеется свой драйвер . Внутри них вызывается стандартный роутинг - "netif_rx [net/core/dev.c]". Что происходит , когда приходит TCP-пакет :
   |netif_rx
      |__skb_queue_tail
         |qlen++
         |* simple pointer insertion *
      |cpu_raise_softirq
         |softirq_active(cpu) |= (1 << NET_RX_SOFTIRQ) 
         // set bit NET_RX_SOFTIRQ in the BH vector
NET_RX_SOFTIRQ генерирует вызов ''net_rx_action [net/core/dev.c]''
   |net_rx_action
      |skb = __skb_dequeue (the exact opposite of __skb_queue_tail)
      |for (ptype = first_protocol; ptype < max_protocol; ptype++) 
         |if (skb->protocol == ptype)                              
            |ptype->func -> ip_rcv 
       **** NOW WE KNOW THAT PACKET IS IP ****
            |ip_rcv
               |NF_HOOK (ip_rcv_finish)
                  |ip_route_input 
                     |skb->dst->input -> ip_local_deliver 
                        |ip_defrag // reassembles IP fragments
                           |NF_HOOK (ip_local_deliver_finish)
                              |ipprot->handler -> tcp_v4_rcv 
 
        **** NOW WE KNOW THAT PACKET IS TCP ****
                              |tcp_v4_rcv
                                 |sk = __tcp_v4_lookup
                                 |tcp_v4_do_rcv
                                    |switch(sk->state)
 
 Packet can be sent to the task which uses relative socket ***
                                 |case TCP_ESTABLISHED:
                                 |tcp_rcv_established
                                 |__skb_queue_tail // enqueue packet to socket
                                 |sk->data_ready -> sock_def_readable
                                 |wake_up_interruptible
 
 
        *** Packet has still to be handshaked by 3-way TCP handshake ***
                                    |case TCP_LISTEN:
                                       |tcp_v4_hnd_req
                                          |tcp_v4_search_req
                                          |tcp_check_req
                                          |syn_recv_sock -> tcp_v4_syn_recv_sock
                                          |__tcp_v4_lookup_established
                                    |tcp_rcv_state_process
 
                 *** 3-Way TCP Handshake ***
                                 |switch(sk->state)
                                 |case TCP_LISTEN: // We received SYN
                                         |conn_request -> tcp_v4_conn_request
                                         |tcp_v4_send_synack // Send SYN + ACK
                                         |tcp_v4_synq_add // set SYN state
                                 |case TCP_SYN_SENT: // we received SYN + ACK
                                         |tcp_rcv_synsent_state_process
                                         tcp_set_state(TCP_ESTABLISHED)
                                         |tcp_send_ack
                                                 |tcp_transmit_skb
                                                 |queue_xmit -> ip_queue_xmit
                                                         |ip_queue_xmit2
                                                         |skb->dst->output
                                 |case TCP_SYN_RECV: // We received ACK
                                         |if (ACK)
                                         |tcp_set_state(TCP_ESTABLISHED)
Т.о. вначале мы определяем тип протокола (сначала IP , потом TCP) Функция NF_HOOK (function) управляет сетевым фильтром. После чего идет реализация классического TCP-рукопожатия - 3-way TCP Handshake :
   SERVER (LISTENING)                       CLIENT (CONNECTING)
                              SYN
                      <-------------------
                           SYN + ACK
                      ------------------->
                              ACK
                      <-------------------
                       3-Way TCP handshake
В случае успеха вызываем "tcp_rcv_established[net/ipv4/tcp_input.c]" .

  Стек используется для
   1. хранения глобальных переменных
   2. хранения локальных переменных
   3. возвращения адресов
 Например , при вызове функции c n-параметрами :
    |int foo_function (parameter_1, parameter_2, ..., parameter_n) {
       |variable_1 declaration;
       |variable_2 declaration;
         ..
       |variable_n declaration;
       |// Body function
       |dynamic variable_1 declaration;
       |dynamic variable_2 declaration;
        ..
       |dynamic variable_n declaration;
 
       |// Code in Code Segment
       |return (ret-type) value
    |}
   мы имеем :
             |                       |
             | 1. parameter_1 pushed | \
       S     | 2. parameter_2 pushed |  | Before
       T     | ...................   |  | the calling
       A     | n. parameter_n pushed | /
       C     | ** Return address **  | -- Calling
       K     | 1. local variable_1   | \
             | 2. local variable_2   |  | After
             | .................     |  | the calling
             | n. local variable_n   | /
             |                       |
            ...                     ...   Free
            ...                     ...   stack
             |                       |
       H     | n. dynamic variable_n | \
       E     | ...................   |  | Allocated by
       A     | 2. dynamic variable_2 |  | malloc & kmalloc
       P     | 1. dynamic variable_1 | /
             |_______________________|
Чем различаются понятия - приложение - и - процесс ? Приложение - это исполняемый код . Процесс - образ памяти , которую использует приложение . Синонимом для - процесса - являются понятия - задача - или - тред .

Copy_on_write - механизм для уменьшения используемой памяти . Например , когда какая-то задача порождает другой процесс , он выполняется внутри ее страниц памяти с правами read-only , и если только возникает необходимость для записи данных в память , тогда страницы памяти родителя будут скопированы с правами write .
 Схема механизма прерываний :
                                    |<-->  IRQ(0) [Timer]
                                    |<-->  IRQ(1) [Device 1]
                                    | ..
                                    |<-->  IRQ(n) [Device n]
       _____________________________|
        /|\      /|\          /|\
         |        |            |
        \|/      \|/          \|/
       Task(1)  Task(2) ..   Task(N)
 
Под линуксом , любой ресурс часто бывает задействован между несколькими обьектами , и нужна очередь для распределения доступа к этому ресурсу . Эта очередь называется "wait queue" ":
   ***   wait queue structure [include/linux/wait.h]  ***
   struct __wait_queue {
      unsigned int flags;
      struct task_struct * task;
      struct list_head task_list;
   }
   struct list_head {
      struct list_head *next, *prev;
   };
 Графическая схема :
           ***  wait queue element  ***
                                /|\
                                 |
          <--[prev *, flags, task *, next *]-->
 
                    ***  wait queue list ***
 
             /|\           /|\           /|\                /|\
              |             |             |                  |
       <--[task1]--> <--[task2]--> <--[task3]--> .... <--[taskN]
   |                                                           |
   _____________________________________________________|
 
 
                 ***   wait queue head ***
          task1 <--[prev *, lock, next *]--> taskN
"wait queue head" указывает на первый и последний элементы в очереди "wait queue list". Когда новый элемент добавляется , вызывается "__add_wait_queue" , затем "list_add":
   ***   function list_add [include/linux/list.h]  ***
   // classic double link list insert
   static __inline__ void __list_add (struct list_head * new,  \
                                      struct list_head * prev, \
                                      struct list_head * next) {
      next->prev = new;
      new->next = next;
      new->prev = prev;
      prev->next = new;
   }
Линукс написан на чистом ''C'' , и существуют следующие типы переменных :
   1. Локальные переменные
   2. Переменные модуля
   3. Глобальные статические переменные , 
         видимые во всех модулях
 
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье
Natalia
  GOOD
2013-04-09 19:53:49