In Linux, the process scheduler is a core part of the kernel. It doesn’t exist as a separate thread, or module, it’s implemented as a function, __schedule()
.
The job of the process scheduler is to decide which process should run next. Each processor in the system has a runqueue, which is the list of processes which are waiting to run on the CPU. When it’s invoked, the scheduler looks at this list of processes, and decides which one to run next; this can be the process (or rather, thread) which was running previously, or it could be another one. Various other systems in the kernel add and remove tasks from the runqueue, or move them from one CPU’s runqueue to another.
The kernel will reschedule processes in a number of circumstances: whenever a process is blocked (by a semaphore, mutex etc.), and whenever a reschedule has been requested and the system transitions from userspace to the kernel or back. The timer tick doesn’t directly invoke the scheduler, it requests a reschedule.