170 likes | 179 Views
Explore historical solutions, synchronization primitives, concurrency concepts, and working with semaphores in depth. Learn about Peterson's and Dekker's algorithms, per-CPU variables, atomic operations, memory barriers, spin locks, and more.
E N D
Synchronization September 15, 2006 These people do not actually work at RightNow.
Outline • Historical solutions • Synchronization Primitives • Brief word on concurrency • Semaphores in depth • semid_ds • sem • Working with semaphores • References
Peterson's Algorithm //Thread A: lockA = true; turn = B; while( lockB && turn != A ) { } lockA = false; //Thread B: lockB = true; turn = A; while( lockA && turn != B ) { } lockB = false; boolean lockA = lockB = false; int turn = A; // or B
Dekker's Algorithm //Thread A: lockA = true; while(lockB) { if (turn != A) { lockA = false; while(turn != A){} lockA = true; } } lockA = false; turn = B; //Thread B: lockB = true; while(lockA) { if (turn != B) { lockB = false; while(turn != B){} lockB = true; } } lockB = false; turn = A; boolean lockA = lockB = false; int turn = A; // or B
Synchronization Primitives • Per-CPU variables • Atomic operation • Memory barrier • Spin lock • Seqlocks • Read-copy-update • Semaphore • Local interrupt disabling • Local softirq disabling
Synchronization Primitives – cont. • Per-CPU Variables • Array of data structures that can be accessed by only 1 CPU • Only useful when data can be split across CPUs • Fails if kernel preemption is enabled (race conditions) • Atomic operation • Read-modify-write • atomic_read(v) • atomic_set(v, i) – (test & set) • atomic_add(i, v) • Another set operates on bit masks
Synchronization Primitives – cont. • Memory barrier • Avoids code optimization problems by creating a barrier that ensures that all code before the barrier gets executed before code after the barrier • Spin locks • Busy wait while blocked • Useful for multi-processor systems when the critical code will execute very fast • 1 = unlocked, 0 = locked • Read/Write Spin Locks
Synchronization Primitives – cont. • Seqlocks • Read/Write spin locks that give high priority to writers • Read-Copy Update • Allows many readers and writers • No locks or counters • Writer just copies the old data, updates it and changes the pointer • Old data cannot be freed until all readers are finished
Synchronization Primitives – cont. • Semaphores • Kernel and System V IPC (User) • count • If count > 0 the resource is free • count = 0 means the resource is 100% utilized but the wait queue is empty • If count < 0 the resource is 100% utilized and there are processes in the wait queue • wait – pointer to the wait queue • sleepers – flag that is set if there are processes that are waiting blocked • More to come!
Synchronization Primitives – cont. • Local Interrupt Disabling • Creates a critical section in the kernel so that even hardware interrupts won’t break the execution of a set of statements • CPU specific • Local softirq disabling • Disable deferrable functions w/o disabling interrupts • Increment the softirq counter to disable; decrement the softirq counter to enable
++ Concurrency • Maximize the number of I/O devices operating • Disable interrupts for very short periods • Maximize the number of productive CPUs • Avoid using spin locks if possible
/* One semid data structure for each set of semaphores in the system. */ struct semid_ds { struct ipc_perm sem_perm; /* permissions .. see ipc.h */ time_t sem_otime; /* last semop time */ time_t sem_ctime; /* last change time */ struct sem *sem_base; /* ptr to first semaphore in array */ struct wait_queue *eventn; struct wait_queue *eventz; struct sem_undo *undo; /* undo requests on this array */ ushort sem_nsems; /* no. of semaphores in array */ }; sem_perm This is an instance of the ipc_perm structure, which is defined for us in linux/ipc.h. This holds the permission information for the semaphore set, including the access permissions, and information about the creator of the set (uid, etc). sem_otime Time of the last semop() operation sem_ctime Time of the last change to this structure (mode change, etc) sem_base Pointer to the first semaphore in the array (see next structure) sem_undo Number of undo requests in this array sem_nsems Number of semaphores in the semaphore set (the array) More on Semaphores (semid_ds)
/* One semaphore structure for each semaphore in the system. */ struct sem { short sempid; /* pid of last operation */ ushort semval; /* current value */ ushort semncnt; /* num procs awaiting increase in semval */ ushort semzcnt; /* num procs awaiting semval = 0 */ }; sem_pid The PID (process ID) that performed the last operation sem_semval The current value of the semaphore sem_semncnt Number of processes waiting for resources to become available sem_semzcnt Number of processes waiting for 100% resource utilization More on Semaphores (sem)
Working with Semaphores int semget ( key_t key, int nsems, int semflg ); int semop ( int semid, struct sembuf *sops, unsigned nsops); struct sembuf { ushort sem_num; /* semaphore index in array */ short sem_op; /* semaphore operation */ short sem_flg; /* operation flags */ };
Working with Semaphores – cont. int semctl ( int semid, int semnum, int cmd, union semun arg ); union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ ushort *array; /* array for GETALL & SETALL */ struct seminfo *__buf; /* buffer for IPC_INFO */ void *__pad; };
IPC_STAT Retrieves the semid_ds structure for a set, and stores it in the address of the buf argument in the semun union. IPC_SET Sets the value of the ipc_perm member of the semid_ds structure for a set. Takes the values from the buf argument of the semun union. IPC_RMID Removes the set from the kernel. GETALL Used to obtain the values of all semaphores in a set. The integer values are stored in an array of unsigned short integers pointed to by the array member of the union. GETNCNT Returns the number of processes currently waiting for resources. GETPID Returns the PID of the process which performed the last semop call. GETVAL Returns the value of a single semaphore within the set. GETZCNT Returns the number of processes currently waiting for 100% resource utilization. SETALL Sets all semaphore values with a set to the matching values contained in the array member of the union. SETVAL Sets the value of an individual semaphore within the set to the val member of the union. Semaphore Commands
References • D. Bovet and M. Cesati. Understanding the Linux Kernel, Third Edition.O'Reilly and Associates, Inc., 2002. • The Linux Documentation Project: http://www.tldp.org/LDP/lpg/node46.html • R. Kline. Peterson's Algorithm, 2006. http://www.cs.wcupa.edu/~rkline/OS/Peterson.html