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 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);

This is also a good place to recall from the introduction that Linux sometimes has to return a pointer if an operation succeeds, and an error code if something fails. Unfortunately, the C language only allows a single direct return value per function, so any information about possible errors has to be encoded into the pointer. While pointers can in general point to arbitrary locations in memory, each architecture supported by Linux has a region in virtual address space that starts from virtual address 0 and goes at least 4 KiB far where no senseful information can live. The kernel can thus reuse this pointer range to encode error codes: If the return value of fork points to an address within the aforementioned range, then the call has failed, and the reason can be determined by the numerical value of the pointer. err_ptr is a helper macro to perform the encoding of the numerical constant -einval (invalid operation) into a pointer.

Some further flag checks are required:

□ When a thread is created with clone_thread, signal sharing must be activated with clone_sighand. Individual threads in a thread group cannot be addressed by a signal.

□ Shared signal handlers can only be provided if the virtual address space is shared between parent and child (clone_vm). Transitive thinking reveals that threads, therefore, also have to share the address space with the parent.

Once the kernel has established that the flag set does not contradict itself, dup_task_struct is used to create an identical copy of the task structure of the parent process. The new task_struct instance for the child can be allocated at any point in kernel memory that happens to be free (see Chapter 3, in which the allocation mechanisms used for this purpose are described).

The task structures for parent and child differ only in one element: A new kernel mode stack is allocated for the new process. A pointer to it is stored in task_struct->stack. Usually the stack is stored in a union with thread_info, which holds all required processor-specific low-level information about the thread.

Continue reading here: Info

Was this article helpful?

0 0