10.07.2015 Views

Is Parallel Programming Hard, And, If So, What Can You Do About It?

Is Parallel Programming Hard, And, If So, What Can You Do About It?

Is Parallel Programming Hard, And, If So, What Can You Do About It?

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

8.2. REFERENCE COUNTING 75ure. Otherwise, if the attempt is successful, lines 14-15 exit the read-side critical section and return apointer to the file structure.The fcheck_files() primitive is a helper functionfor fget(). <strong>It</strong> uses the rcu_dereference()primitive to safely fetch an RCU-protected pointerfor later dereferencing (this emits a memory barrieron CPUs such as DEC Alpha in which data dependenciesdo not enforce memory ordering). Line 22uses rcu_dereference() to fetch a pointer to thistask’scurrentfile-descriptortable, andline24checksto see if the specified file descriptor is in range. <strong>If</strong> so,line 25 fetches the pointer to the file structure, againusing the rcu_dereference() primitive. Line 26then returns a pointer to the file structure or NULLin case of failure.The fput() primitive releases a reference to a filestructure. Line 31 atomically decrements the referencecount,and, iftheresultwaszero,line32invokesthecall_rcu()primitives inordertofreeupthefilestructure (via the file_free_rcu() function specifiedin call_rcu()’s second argument), but onlyafter all currently-executing RCU read-side criticalsections complete. The time period required for allcurrently-executing RCU read-side critical sectionsto complete is termed a “grace period”. Note thatthe atomic_dec_and_test() primitive contains amemory barrier. This memory barrier is not necessaryin this example, since the structure cannotbe destroyed until the RCU read-side critical sectioncompletes, but in Linux, all atomic operations thatreturn a result must by definition contain memorybarriers.Once the grace period completes, the file_free_rcu() function obtains a pointer to the file structureon line 39, and frees it on line 40.This approach is also used by Linux’s virtualmemorysystem, see get_page_unless_zero() andput_page_testzero() for page structures as wellas try_to_unuse() and mmput() for memory-mapstructures.8.2.2 Linux Primitives SupportingReference CountingThe Linux-kernel primitives used in the above examplesare summarized in the following list.• atomic t Type definition for 32-bit quantityto be manipulated atomically.• void atomic dec(atomic t *var); Atomicallydecrements the referenced variable withoutnecessarily issuing a memory barrier or disablingcompiler optimizations.• int atomic dec and test(atomic t*var); Atomically decrements the referencedvariable, returning TRUE if the resultis zero. <strong>Is</strong>sues a memory barrier and disablescompiler optimizations that might otherwisemove memory references across this primitive.• void atomic inc(atomic t *var); Atomicallyincrements the referenced variable withoutnecessarily issuing a memory barrier or disablingcompiler optimizations.• int atomic inc not zero(atomic t*var); Atomically increments the referencedvariable, but only if the value isnon-zero, and returning TRUE if the incrementoccurred. <strong>Is</strong>sues a memory barrier and disablescompiler optimizations that might otherwisemove memory references across this primitive.• int atomic read(atomic t *var); Returnsthe integer value of the referenced variable.This is not an atomic operation, and it neitherissues memory barriers nor disables compileroptimizations.• void atomic set(atomic t *var, intval); Sets the value of the referencedatomic variable to “val”. This is not anatomic operation, and it neither issues memorybarriers nor disables compiler optimizations.• void call rcu(struct rcu head*head, void (*func)(struct rcu head*head)); Invokes func(head) some timeafter all currently executing RCU readsidecritical sections complete, however, thecall_rcu() primitive returns immediately.Note that head is normally a field withinan RCU-protected data structure, and thatfunc is normally a function that frees up thisdata structure. The time interval between theinvocation of call_rcu() and the invocation offunc is termed a “grace period”. Any intervalof time containing a grace period is itself agrace period.• type *container of(p, type, f); Given apointer “p” to a field “f” within a structure ofthe specified type, return a pointer to the structure.• void rcu read lock(void); Marks the beginningof an RCU read-side critical section.• void rcu read unlock(void); Marks theend of an RCU read-side critical section. RCUread-side critical sections may be nested.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!