sys_fork(), sys_vfork(), sys_clone()각 함수들이 내부적으로 do_fork()함수를 호출하고있는것을 볼 수 있습니다. 각 함수는 x86 버젼입니다. =========================================================================================== int sys_fork(struct pt_regs *regs) { return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); } 일단 함수 내부를 보면 다음과 같습니다. do_fork()함수에 인자로 쓰이는pt_regs구조체를 보면, 다음과 같습니다. pt_regs구조체는 시스템 콜중에, 레지스터를 스텍에 저장하기 위해 사용된다고 합니다. struct pt_regs { unsigned long bx; unsigned long cx; unsigned long dx; unsigned long si; unsigned long di; unsigned long bp; unsigned long ax; unsigned long ds; unsigned long es; unsigned long fs; unsigned long gs; unsigned long orig_ax; unsigned long ip; unsigned long cs; unsigned long flags; unsigned long sp; unsigned long ss; }; int sys_vfork(struct pt_regs *regs) { return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, NULL, NULL); } long sys_clone(unsigned long clone_flags, unsigned long newsp, void __user *parent_tid, void __user *child_tid, struct pt_regs *regs) { if (!newsp) newsp = regs->sp; return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); } long do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) { struct task_struct *p; int trace = 0; long nr; /* * Do some preliminary argument and permissions checking before we * actually start allocating stuff */ if (clone_flags & CLONE_NEWUSER) { if (clone_flags & CLONE_THREAD) return -EINVAL; /* hopefully this check will go away when userns support is * complete */ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SETUID) || !capable(CAP_SETGID)) return -EPERM; } /* * We hope to recycle these flags after 2.6.26 */ if (unlikely(clone_flags & CLONE_STOPPED)) { static int __read_mostly count = 100; if (count > 0 && printk_ratelimit()) { char comm[TASK_COMM_LEN]; count--; printk(KERN_INFO "fork(): process `%s' used deprecated " "clone flags 0x%lxn", get_task_comm(comm, current), clone_flags & CLONE_STOPPED); } } /* * When called from kernel_thread, don't do user tracing stuff. */ if (likely(user_mode(regs))) trace = tracehook_prepare_clone(clone_flags); p = copy_process(clone_flags, stack_start, regs, stack_size, child_tidptr, NULL, trace); /* * Do this prior waking up the new thread - the thread pointer * might get invalid after that point, if the thread exits quickly. */ if (!IS_ERR(p)) { struct completion vfork; trace_sched_process_fork(current, p); nr = task_pid_vnr(p); if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); } audit_finish_fork(p); tracehook_report_clone(regs, clone_flags, nr, p); /* * We set PF_STARTING at creation in case tracing wants to * use this to distinguish a fully live task from one that * hasn't gotten to tracehook_report_clone() yet. Now we * clear it and set the child going. */ p->flags &= ~PF_STARTING; if (unlikely(clone_flags & CLONE_STOPPED)) { /* * We'll start up with an immediate SIGSTOP. */ sigaddset(&p->pending.signal, SIGSTOP); set_tsk_thread_flag(p, TIF_SIGPENDING); __set_task_state(p, TASK_STOPPED); } else { wake_up_new_task(p, clone_flags); } tracehook_report_clone_complete(trace, regs, clone_flags, nr, p); if (clone_flags & CLONE_VFORK) { freezer_do_not_count(); wait_for_completion(&vfork); freezer_count(); tracehook_report_vfork_done(p, nr); } } else { nr = PTR_ERR(p); } return nr; } do_fork()함수를 보면, 내부적으로 copy_process함수를 호출합니다. copy_process함수내부를보면, 인자로 받은값들은 task_struct에 넣어주고 있습니다. 그리고 이렇게 넣어준값들로 sched_fork()함수를 호출합니다. 이 함수에서는 task_struct를 가지고 cpu에 할당해주고있는것을 추측해볼 수 있습니다. do_fork() -> copy_process() -> sched_fork() ============================================================================================ static struct task_struct *copy_process(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *child_tidptr, struct pid *pid, int trace) { int retval; struct task_struct *p; int cgroup_callbacks_done = 0; if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) return ERR_PTR(-EINVAL); /* * Thread groups must share signals as well, and detached threads * can only be started up within the thread group. */ if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND)) return ERR_PTR(-EINVAL); /* * Shared signal handlers imply shared VM. By way of the above, * thread groups also imply shared VM. Blocking this case allows * for various simplifications in other code. */ if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM)) return ERR_PTR(-EINVAL); /* * Siblings of global init remain as zombies on exit since they are * not reaped by their parent (swapper). To solve this and to avoid * multi-rooted process trees, prevent global and container-inits * from creating siblings. */ if ((clone_flags & CLONE_PARENT) && current->signal->flags & SIGNAL_UNKILLABLE) return ERR_PTR(-EINVAL); retval = security_task_create(clone_flags); if (retval) goto fork_out; retval = -ENOMEM; p = dup_task_struct(current); if (!p) goto fork_out; ftrace_graph_init_task(p); rt_mutex_init_task(p); #ifdef CONFIG_PROVE_LOCKING DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled); DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled); #endif retval = -EAGAIN; if (atomic_read(&p->real_cred->user->processes) >= p->signal->rlim[RLIMIT_NPROC].rlim_cur) { if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) && p->real_cred->user != INIT_USER) goto bad_fork_free; } retval = copy_creds(p, clone_flags); if (retval < 0) goto bad_fork_free; /* * If multiple threads are within copy_process(), then this check * triggers too late. This doesn't hurt, the check is only there * to stop root fork bombs. */ retval = -EAGAIN; if (nr_threads >= max_threads) goto bad_fork_cleanup_count; if (!try_module_get(task_thread_info(p)->exec_domain->module)) goto bad_fork_cleanup_count; p->did_exec = 0; delayacct_tsk_init(p); /* Must remain after dup_task_struct() */ copy_flags(clone_flags, p); INIT_LIST_HEAD(&p->children); INIT_LIST_HEAD(&p->sibling); rcu_copy_process(p); p->vfork_done = NULL; spin_lock_init(&p->alloc_lock); init_sigpending(&p->pending); p->utime = cputime_zero; p->stime = cputime_zero; p->gtime = cputime_zero; p->utimescaled = cputime_zero; p->stimescaled = cputime_zero; #ifndef CONFIG_VIRT_CPU_ACCOUNTING p->prev_utime = cputime_zero; p->prev_stime = cputime_zero; #endif p->default_timer_slack_ns = current->timer_slack_ns; task_io_accounting_init(&p->ioac); acct_clear_integrals(p); posix_cpu_timers_init(p); p->lock_depth = -1; /* -1 = no lock */ do_posix_clock_monotonic_gettime(&p->start_time); p->real_start_time = p->start_time; monotonic_to_bootbased(&p->real_start_time); p->io_context = NULL; p->audit_context = NULL; cgroup_fork(p); #ifdef CONFIG_NUMA p->mempolicy = mpol_dup(p->mempolicy); if (IS_ERR(p->mempolicy)) { retval = PTR_ERR(p->mempolicy); p->mempolicy = NULL; goto bad_fork_cleanup_cgroup; } mpol_fix_fork_child_flag(p); #endif #ifdef CONFIG_TRACE_IRQFLAGS p->irq_events = 0; #ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW p->hardirqs_enabled = 1; #else p->hardirqs_enabled = 0; #endif p->hardirq_enable_ip = 0; p->hardirq_enable_event = 0; p->hardirq_disable_ip = _THIS_IP_; p->hardirq_disable_event = 0; p->softirqs_enabled = 1; p->softirq_enable_ip = _THIS_IP_; p->softirq_enable_event = 0; p->softirq_disable_ip = 0; p->softirq_disable_event = 0; p->hardirq_context = 0; p->softirq_context = 0; #endif #ifdef CONFIG_LOCKDEP p->lockdep_depth = 0; /* no locks held yet */ p->curr_chain_key = 0; p->lockdep_recursion = 0; #endif #ifdef CONFIG_DEBUG_MUTEXES p->blocked_on = NULL; /* not blocked yet */ #endif #ifdef CONFIG_CGROUP_MEM_RES_CTLR p->memcg_batch.do_batch = 0; p->memcg_batch.memcg = NULL; #endif p->bts = NULL; p->stack_start = stack_start; /* Perform scheduler related setup. Assign this task to a CPU. */ sched_fork(p, clone_flags); retval = perf_event_init_task(p); if (retval) goto bad_fork_cleanup_policy; if ((retval = audit_alloc(p))) goto bad_fork_cleanup_policy; /* copy all the process information */ if ((retval = copy_semundo(clone_flags, p))) goto bad_fork_cleanup_audit; if ((retval = copy_files(clone_flags, p))) goto bad_fork_cleanup_semundo; if ((retval = copy_fs(clone_flags, p))) goto bad_fork_cleanup_files; if ((retval = copy_sighand(clone_flags, p))) goto bad_fork_cleanup_fs; if ((retval = copy_signal(clone_flags, p))) goto bad_fork_cleanup_sighand; if ((retval = copy_mm(clone_flags, p))) goto bad_fork_cleanup_signal; if ((retval = copy_namespaces(clone_flags, p))) goto bad_fork_cleanup_mm; if ((retval = copy_io(clone_flags, p))) goto bad_fork_cleanup_namespaces; retval = copy_thread(clone_flags, stack_start, stack_size, p, regs); if (retval) goto bad_fork_cleanup_io; if (pid != &init_struct_pid) { retval = -ENOMEM; pid = alloc_pid(p->nsproxy->pid_ns); if (!pid) goto bad_fork_cleanup_io; if (clone_flags & CLONE_NEWPID) { retval = pid_ns_prepare_proc(p->nsproxy->pid_ns); if (retval < 0) goto bad_fork_free_pid; } } p->pid = pid_nr(pid); p->tgid = p->pid; if (clone_flags & CLONE_THREAD) p->tgid = current->tgid; if (current->nsproxy != p->nsproxy) { retval = ns_cgroup_clone(p, pid); if (retval) goto bad_fork_free_pid; } p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; /* * Clear TID on mm_release()? */ p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr: NULL; #ifdef CONFIG_FUTEX p->robust_list = NULL; #ifdef CONFIG_COMPAT p->compat_robust_list = NULL; #endif INIT_LIST_HEAD(&p->pi_state_list); p->pi_state_cache = NULL; #endif /* * sigaltstack should be cleared when sharing the same VM */ if ((clone_flags & (CLONE_VM|CLONE_VFORK)) == CLONE_VM) p->sas_ss_sp = p->sas_ss_size = 0; /* * Syscall tracing and stepping should be turned off in the * child regardless of CLONE_PTRACE. */ user_disable_single_step(p); clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); #ifdef TIF_SYSCALL_EMU clear_tsk_thread_flag(p, TIF_SYSCALL_EMU); #endif clear_all_latency_tracing(p); /* ok, now we should be set up.. */ p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL); p->pdeath_signal = 0; p->exit_state = 0; /* * Ok, make it visible to the rest of the system. * We dont wake it up yet. */ p->group_leader = p; INIT_LIST_HEAD(&p->thread_group); /* Now that the task is set up, run cgroup callbacks if * necessary. We need to run them before the task is visible * on the tasklist. */ cgroup_fork_callbacks(p); cgroup_callbacks_done = 1; /* Need tasklist lock for parent etc handling! */ write_lock_irq(&tasklist_lock); /* CLONE_PARENT re-uses the old parent */ if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) { p->real_parent = current->real_parent; p->parent_exec_id = current->parent_exec_id; } else { p->real_parent = current; p->parent_exec_id = current->self_exec_id; } spin_lock(¤t->sighand->siglock); /* * Process group and session signals need to be delivered to just the * parent before the fork or both the parent and the child after the * fork. Restart if a signal comes in before we add the new process to * it's process group. * A fatal signal pending means that current will exit, so the new * thread can't slip out of an OOM kill (or normal SIGKILL). */ recalc_sigpending(); if (signal_pending(current)) { spin_unlock(¤t->sighand->siglock); write_unlock_irq(&tasklist_lock); retval = -ERESTARTNOINTR; goto bad_fork_free_pid; } if (clone_flags & CLONE_THREAD) { atomic_inc(¤t->signal->count); atomic_inc(¤t->signal->live); p->group_leader = current->group_leader; list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group); } if (likely(p->pid)) { tracehook_finish_clone(p, clone_flags, trace); if (thread_group_leader(p)) { if (clone_flags & CLONE_NEWPID) p->nsproxy->pid_ns->child_reaper = p; p->signal->leader_pid = pid; tty_kref_put(p->signal->tty); p->signal->tty = tty_kref_get(current->signal->tty); attach_pid(p, PIDTYPE_PGID, task_pgrp(current)); attach_pid(p, PIDTYPE_SID, task_session(current)); list_add_tail(&p->sibling, &p->real_parent->children); list_add_tail_rcu(&p->tasks, &init_task.tasks); __get_cpu_var(process_counts)++; } attach_pid(p, PIDTYPE_PID, pid); nr_threads++; } total_forks++; spin_unlock(¤t->sighand->siglock); write_unlock_irq(&tasklist_lock); proc_fork_connector(p); cgroup_post_fork(p); perf_event_fork(p); return p; bad_fork_free_pid: if (pid != &init_struct_pid) free_pid(pid); bad_fork_cleanup_io: if (p->io_context) exit_io_context(p); bad_fork_cleanup_namespaces: exit_task_namespaces(p); bad_fork_cleanup_mm: if (p->mm) mmput(p->mm); bad_fork_cleanup_signal: if (!(clone_flags & CLONE_THREAD)) __cleanup_signal(p->signal); bad_fork_cleanup_sighand: __cleanup_sighand(p->sighand); bad_fork_cleanup_fs: exit_fs(p); /* blocking */ bad_fork_cleanup_files: exit_files(p); /* blocking */ bad_fork_cleanup_semundo: exit_sem(p); bad_fork_cleanup_audit: audit_free(p); bad_fork_cleanup_policy: perf_event_free_task(p); #ifdef CONFIG_NUMA mpol_put(p->mempolicy); bad_fork_cleanup_cgroup: #endif cgroup_exit(p, cgroup_callbacks_done); delayacct_tsk_free(p); module_put(task_thread_info(p)->exec_domain->module); bad_fork_cleanup_count: atomic_dec(&p->cred->user->processes); exit_creds(p); bad_fork_free: free_task(p); fork_out: return ERR_PTR(retval); } void sched_fork(struct task_struct *p, int clone_flags) { int cpu = get_cpu(); __sched_fork(p); /* * We mark the process as waking here. This guarantees that * nobody will actually run it, and a signal or other external * event cannot wake it up and insert it on the runqueue either. */ p->state = TASK_WAKING; /* * Revert to default priority/policy on fork if requested. */ if (unlikely(p->sched_reset_on_fork)) { if (p->policy == SCHED_FIFO || p->policy == SCHED_RR) { p->policy = SCHED_NORMAL; p->normal_prio = p->static_prio; } if (PRIO_TO_NICE(p->static_prio) < 0) { p->static_prio = NICE_TO_PRIO(0); p->normal_prio = p->static_prio; set_load_weight(p); } /* * We don't need the reset flag anymore after the fork. It has * fulfilled its duty: */ p->sched_reset_on_fork = 0; } /* * Make sure we do not leak PI boosting priority to the child. */ p->prio = current->normal_prio; if (!rt_prio(p->prio)) p->sched_class = &fair_sched_class; if (p->sched_class->task_fork) p->sched_class->task_fork(p); set_task_cpu(p, cpu); #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) if (likely(sched_info_on())) memset(&p->sched_info, 0, sizeof(p->sched_info)); #endif #if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW) p->oncpu = 0; #endif #ifdef CONFIG_PREEMPT /* Want to start with kernel preemption disabled. */ task_thread_info(p)->preempt_count = 1; #endif plist_node_init(&p->pushable_tasks, MAX_PRIO); put_cpu(); }
댓글 7
-
김종혁
2010.04.19 10:06
-
백창우
2010.04.19 11:40
음... 그렇군요. 시간날 때 제로보드 플러그인을 한번 찾아보도록 하겠습니다.
-
백창우
2010.04.20 01:21
음... 잘못한거 없으십니다. 방금 제 오해는 풀렸습니다.
처음 글에서 제가 느낀것은 게시판에 문제가 있다고 저에게 질타한다고 생각했습니다.
고칠점이 있다면 그점에 대해서 말해주면 되는데 왜 질타를 할까? 라고 생각했습니다.
"게시판이 소스 보기가 너무 않 좋네!"
이 표현이 그렇게 느껴지게 하더군요.
저도 멤버중에 하나인 마당에 홈페이지 관리에 서버 관리에 기타 잡일들을 함께 처리하는데,
좀 서운하다는 생각도 들었습니다.
다른분에게 하신 말씀이라는 것은 이 글을 읽고 나서야 알았습니다.
-
김종혁
2010.04.20 00:34
음, 길게 글을 적어주셨는데,,, 저는 딱히 할말이 없군요!
백창우님이 정해 놓은 가이드라인에 제가 어울리지 않는다는 생각만 드는군요.
스터디를 먼저 진행하신 선배로써, 해주신 여러가지 조언은 잘 기억하고 있습니다.
하지만 그것이 모든 상황에 최적이고 옳은것이라 생각하지는 않습니다. 저와 같은 반론이 있어야,,,
스터디는 더 발전하고 앞으로 나가는것 아니겠습니까? 무조건 따르기만 한다면... 옳은것은 아니라 생각이 드는데...
저는 잘 모르겠습니다. 제가 무엇을 잘못했는지...
오늘도 술한잔 마시고 들어와서, 잠들기전에 사이트에 접속해 보았는데,,,
내일 맑은 정신으로 다시 글을 올리도록 하겠습니다!
-
백창우
2010.04.19 19:23
금번 글은 소그룹에 대한 이야기가 아닌, 어떤 분의 말씀에 대한 글이였습니다.
그 글은 현재 홈페이지를 관리하고 있는 저나 혹은 강진성님이 들었을때 자신과 관련 있다고 생각되는 이야기였습니다.
만약 위 글이 "게시판이 소스 보기가 너무 않 좋네!"가 아니라" 게시판이 소스 보기가 너무 않좋은것 같습니다."라고 표현되었다면 듣는 제 입장에서는 완전히 다르게 받아들였을지도 모릅니다.
같은 말이라도 "아" 다르고 "어" 다르지 않겠습니까.
소그룹에 대한 간섭(?)으로 받아 들이신다면 지나친 비약이라고 말씀드리고 싶습니다.
또한 지금은 장소가 마땅치 않아 소그룹이 따로 운영되고 있어나 그렇다고 해서
소그룹 각각이 독립된 스터디 그룹이라고 보는것도 옳지 않을거라 봅니다.
주말에 모이는 장소는 다르지만,
게시판을 통해 서로 모르는 것에 대해 물어보면서 스터디를 진행해나가고,
기존 멤버들이 분석한 내용도 참고하고, 듣고 싶은 세미나도 함께 선정해서 듣고,
가끔씩 다 같이 모이는 자리도 가지고, 해가 지나서 현재 스터디가 끝나면
또 다시 들고 싶은 스터디에 들어 다 같이 섞이게 되는데,
여기에 B 그룹이다 A 그룹이다라고 나눌 필요가 있을까? 라는 생각이 듭니다.
다 같이 동시대에 같은 길을 걸어가는 인생의 동료로써 말입니다.
같은 소그룹 내에서 친한것은 당연하나 위와 같은 이유로 다른 그룹에 대해 배타적이지는 않았으면 합니다.
그것은 전체 스터디 그룹이 함께 죽는길이라고 생각합니다.
그렇지만 제가 지나친 간섭을 하는 것은 분명 잘못일겁니다.
그점에 대해서는 저도 항상 주의하고 있고, 무엇이 옳바른 행동일까라고 항상 생각하고 있습니다.
제가 인간이 되었다면 이러한 고민에서 해방되겠지만 아직은 인간이 덜 되어서 항상 고민할 수밖에 없을것 같습니다.
만약 제가 진짜 지나친 간섭을 한다면 그때는 알려주시기 바랍니다.
금번은 소그룹과 전혀 관계 없는 님께서 쓰신 글에 대한 이야기였습니다.
마지막으로 당부드리고 싶은것은 스터디 그룹에서 "막내"란 존재하지 않습니다.
나와 완전히 동등한 멤버만 있을뿐입니다.
한국 사회에 널리 퍼져있는 나이에 대한 관념은 스터디를 망가뜨리는 지름길입니다.현재 나이 40이 넘으신분들도 같은 멤버로써 스터디를 참여하고 계십니다.
제 나이도 그렇지만 30대 초중반 나이는 그분들에 비하면 절대 많은게 아닙니다.
-
김종혁
2010.04.19 18:28
음,,, 뭔가 오해를 하신듯 합니다.
위 댓글은 글을 올린 우리 그룹의 막내분에게 남긴 말이고, 좋은 방법을 찾아보자는 의도였는데,
각 그룹의 게시판에서 듣기 거북하다 백창우님의 댓글이 조금 지나친 간섭(?)이 아닌가 생각됩니다.
좋은 의도로 스터디를 기회를 만들어 주신 점은 감사하지만,,, 위 댓글은 저 또한 조금 듣기 거북하군요!
-
백창우
2010.04.19 18:05
흠. 그리고 앞으로 홈페이지와 관련된 사항은 저 또는 강진성님께 말씀해주시고,
"않 좋네!"와 같은 표현은 자제해주셨으면 합니다. 듣기 거북하군요.
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
공지 | [공지] 커널 스터디 관련 Q&A 게시판 입니다. [5] | woos | 2016.04.09 | 2197 |
125 | 커널7차(x86) B 분들 메일 확인해보세요. [5] | 배병일 | 2010.05.02 | 2750 |
124 | [5월8일] 스터디 참석 여부 댓글로~^^ [3] | 나무꾼 | 2010.05.02 | 1955 |
123 | 5월 1일 스터디 내용 및, 진행방향 [2] | 최문규 | 2010.05.02 | 2981 |
122 | 스터디 존속 여부 [2] | 이재훈 | 2010.05.01 | 1959 |
121 | as86(1) - Linux man page 입니다. | 김민석 | 2010.04.30 | 36679 |
120 | as86 어셈으로 부팅 코드 관련 문서 입니다. | 김민석 | 2010.04.30 | 6114 |
119 | 컥; 저번에 이 문서도 빼먹었네요; | 최문규 | 2010.04.30 | 3459 |
118 | 어떻게 공부하셨나요?? [3] | 김이현 | 2010.04.30 | 2879 |
117 | 제임스몰리의 커널개발 튜토리얼 [1] | 배병일 | 2010.04.30 | 2833 |
116 | 도움이 될만한 사이트 | 배병일 | 2010.04.29 | 2851 |
115 | Windows NT 에서의 시스템 콜 [3] | 박한범 | 2010.04.27 | 2245 |
114 | 4월 24일 스터디 내용 [2] | 최문규 | 2010.04.26 | 2711 |
113 | OS커널의 구조와 원리 책 목차 [1] | 배병일 | 2010.04.26 | 3272 |
112 | Hello World! [1] | 배병일 | 2010.04.21 | 5069 |
111 | g어셈블러, n어셈블러 관련 차이점 | 배병일 | 2010.04.20 | 3010 |
110 | 소스올리실때의 팁(?!) [2] | 최문규 | 2010.04.19 | 2863 |
109 | 커널 동기화 | 배병일 | 2010.04.19 | 3661 |
108 | IA-32 Register 기본 [1] | 배병일 | 2010.04.19 | 2701 |
» | do_fork(), sys_clone()... 분석-수정본 [7] | 최문규 | 2010.04.18 | 10837 |
106 | 4월 17일 스터디 Issue list | 김두균 | 2010.04.18 | 2757 |
.
게시판이 소스 보기가 너무 않 좋네!
적절히 공부 내용을 정리할 다른 방법을 찾아봐야겠는데...