SlideShare ist ein Scribd-Unternehmen logo
1 von 187
Downloaden Sie, um offline zu lesen
Racing To Win
Using Race Conditions to Build
Correct & Concurrent Software
Nathan Taylor | nathan.dijkstracula.net | @dijkstracula
Racing To Win
Using Race Conditions to Build
Correct & Concurrent Software
Nathan Taylor | nathan.dijkstracula.net | @dijkstracula
Hi, I’m Nathan.
( @dijkstracula )
I’m an engineer at
A problem
A problem
A solution
A problem
A solution
Cache node
Cache node
Process A
stack
heap
text
Process B
stack
heap
text
Process C
stack
heap
text
Cache node
Process A
stack
heap
text
Process B
stack
heap
text
Process C
stack
heap
text
A Persistent, Shared-
State Memory Allocator
Cache node
Process A
stack
heap
text
Process B
stack
heap
text
Process C
stack
heap
text
uSlab
Slab allocation
Slab allocation
Object Object Object Object Object Object Object Object
Object Object Object Object Object Object Object Object
s_alloc();
s_alloc();Object
Object
Object
Object Object Object Object Object
s_alloc();
Object
Object
Object
Object Object Object Object Object
Object
Object
Object
Object Object Object Object Object
s_free(	
  	
  	
  	
  	
  	
  	
  );
s_free(	
  	
  	
  	
  	
  	
  	
  );
s_free(	
  	
  	
  	
  	
  	
  	
  );
Object ObjectObject Object Object Object Object Object
Object Object Object Object Object Object Object Object
Object Object Object Object Object Object Object Object
Allocation Protocol
• An request to allocate is followed by a response
containing an object
• A request to free is followed by a response after the
supplied object has been released



• Allocation requests must not respond with an already-
allocated object
• A free request must not release an already-unallocated
object
An Execution History
An Execution History
void foo() {

obj *a = s_alloc();

s_free(a);

…

}
An Execution History
Time
void foo() {

obj *a = s_alloc();

s_free(a);

…

}
A(allocate request)
B(allocate response)
A(free request)
B(free response)
An Execution History
Time
A(allocate request)
B(allocate request)
A(allocate response)
B(allocate response)
An Execution History
Time
A(allocate request)
B(allocate request)
A(allocate response)
B(allocate response)
“X happened before Y” =>
“Y may observe X to have occurred”
A(allocate response)
A(allocate request)
B(allocate request)
B(allocate response)
Time
A(allocate response)
A(allocate request)
B(allocate request)
B(allocate response)
Time
A(allocate response)
A(allocate request)
B(allocate request)
B(allocate response)
A protocol violation!
Time
Time A(allocate response)
A(allocate request)
B(allocate request)
B(allocate response)
Time A(allocate response)
A(allocate request)
B(allocate request)
B(allocate response)
http://cs.brown.edu/~mph/HerlihyW90/p463-herlihy.pdf
A Sequential History
Time
A Sequential History
Time
A(allocate request)
A(allocate response)
A(free request)
A(free response)
B(allocate request)
B(allocate response)
A Sequential History
Time
A(allocate request)
A(allocate response)
{ }
A(free request)
A(free response)
{ }
B(allocate request)
B(allocate response)
{ }
A Sequential History
Time
A(allocate request)
A(allocate response)
{ }
A(free request)
A(free response)
{ }
B(allocate request)
B(allocate response)
{ }
A Sequential History
Time
A(allocate request)
A(allocate response)
{ }
A(free request)
A(free response)
{ }
B(allocate request)
B(allocate response)
{ }
obj	
  *allocate(slab	
  *s)	
  {



	
  	
  obj	
  *a	
  =	
  s-­‐>head;

	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  s-­‐>head	
  =	
  a-­‐>next;



	
  	
  return	
  a;

}	
  
void	
  free(slab	
  *s,	
  obj	
  *o)	
  {

	
  	
  o-­‐>next	
  =	
  s-­‐>head;

	
  	
  s-­‐>head	
  =	
  o;

}
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  lock(&allocator_lock);

	
  	
  obj	
  *a	
  =	
  s-­‐>head;

	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  s-­‐>head	
  =	
  a-­‐>next;

	
  	
  unlock(&allocator_lock);

	
  	
  return	
  a;

}	
  
void	
  free(slab	
  *s,	
  obj	
  *o)	
  {

	
  	
  lock(&allocator_lock);	
  
	
  	
  o-­‐>next	
  =	
  s-­‐>head;

	
  	
  s-­‐>head	
  =	
  o;

	
  	
  unlock(&allocator_lock);	
  
}
Was the State Locked?
Yes
Done
No
Atomic
Fetch Old Lock State
Set State Locked
Was old State Locked?
Yes
Done
No
Atomic
Fetch Old Lock State
Set State Locked
Was old State Locked?
Yes
Done
No
Atomic
Test And Set Lock
Test And Set Unlock
Set State Unlocked
Atomic
typedef	
  spinlock	
  int;

#define	
  LOCKED	
  1

#define	
  UNLOCKED	
  0



void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}	
  
void	
  unlock(spinlock	
  *m)	
  {

	
  	
  atomic_store(m,	
  UNLOCKED);

} Many code examples
derived from Concurrency Kit
http://concurrencykit.org
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
A(TAS request)
A(TAS response)
{ }
A(TAS request)
A(TAS response)
{ }
TAS is embedded in Lock
A(TAS request)
A(TAS response)
{ }
A(lock request)
A(lock response)
Time
TAS is embedded in Lock
A(TAS request)
A(TAS response)
{ }
A(lock request)
A(lock response)
Time
TAS & Store can’t be
reordered
A(TAS request)
A(TAS response)
{ }
A(lock request)
A(lock response)
Time
B(unlock request)
B(unlock response)
B(Store request)
B(Store response)
{ }
TAS & Store can’t be
reordered
All execution histories
All sequentially-consistent
execution histories
⊇
All execution histories
All sequentially-consistent
execution histories
All ???able execution
histories
⊇
⊇
All execution histories
All sequentially-consistent
execution histories
All linearizable execution
histories
⊇
⊇
A(TAS request)
A(TAS response)
{ }
A(lock request)
A(lock response)
Time
Others can be reordered
B(unlock request)
B(unlock response)
B(Store request)
B(Store response)
{ }
A(TAS request)
A(TAS response)
{ }
A(lock request)
A(lock response)
Time
Others can be reordered
B(unlock request)
B(unlock response)
B(Store request)
B(Store response)
{ }
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}	
  
void	
  unlock(spinlock	
  *m)	
  {

	
  	
  atomic_store(m,	
  UNLOCKED);

}
http://dl.acm.org/citation.cfm?id=69624.357207
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  lock(&allocator_lock);

	
  	
  obj	
  *a	
  =	
  s-­‐>head;

	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  s-­‐>head	
  =	
  a-­‐>next;

	
  	
  unlock(&allocator_lock);

	
  	
  return	
  a;

}	
  
void	
  free(slab	
  *s,	
  obj	
  *o)	
  {

	
  	
  lock(&allocator_lock);	
  
	
  	
  o-­‐>next	
  =	
  s-­‐>head;

	
  	
  s-­‐>head	
  =	
  o;

	
  	
  unlock(&allocator_lock);	
  
}
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}	
  
void	
  unlock(spinlock	
  *m)	
  {

	
  	
  atomic_store(m,	
  UNLOCKED);

}
Spinlock performance
millionsoflock
acquisitions/sec
15
30
45
60
75
90
Threads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
87.351
Test and Set
Spinlock performance
millionsoflock
acquisitions/sec
15
30
45
60
75
90
Threads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Platonic ideal of a spinlock
Spinlock performance
millionsoflock
acquisitions/sec
15
30
45
60
75
90
Threads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
87.351
4.343
Test and Set
Spinlock performance
millionsoflock
acquisitions/sec
15
30
45
60
75
90
Threads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Test and Set
Spinlock performance
acquisitions/sec
1E+01
1E+02
1E+03
1E+04
1E+05
1E+06
1E+07
1E+08
Threads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Test and Set
typedef	
  spinlock	
  int;

#define	
  LOCKED	
  1

#define	
  UNLOCKED	
  0



void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}	
  
typedef	
  spinlock	
  int;

#define	
  LOCKED	
  1

#define	
  UNLOCKED	
  0



void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  {

	
  	
  	
  	
  while	
  (atomic_store(m)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  	
  	
  snooze();

	
  	
  }

}	
  
typedef	
  spinlock	
  int;

#define	
  LOCKED	
  1

#define	
  UNLOCKED	
  0



void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  {

	
  	
  	
  	
  while	
  (atomic_store(m)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  	
  	
  snooze();

	
  	
  }

}	
  
Test-and-Test-and-Set
Lockedalloc/free(10s)
10
100
1,000
10,000
100,000
1,000,000
10,000,000
100,000,000
Threads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Test and Set T&T&S
Spinlock performance
Lockedalloc/free(10s)
10
100
1,000
10,000
100,000
1,000,000
10,000,000
100,000,000
Threads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Test and Set T&T&S
typedef	
  spinlock	
  int;

#define	
  LOCKED	
  1

#define	
  UNLOCKED	
  0



void	
  lock(spinlock	
  *m)	
  {	
  
	
  	
  unsigned	
  long	
  backoff,	
  exp	
  =	
  0;	
  

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  {	
  
	
  	
  	
  	
  for	
  (i	
  =	
  0;	
  i	
  <	
  backoff;	
  i++)	
  
	
  	
  	
  	
  	
  	
  snooze();	
  
	
  	
  	
  	
  backoff	
  =	
  (1ULL	
  <<	
  exp++);	
  
	
  	
  }

}	
  
typedef	
  spinlock	
  int;

#define	
  LOCKED	
  1

#define	
  UNLOCKED	
  0



void	
  lock(spinlock	
  *m)	
  {	
  
	
  	
  unsigned	
  long	
  backoff,	
  exp	
  =	
  0;	
  

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  {	
  
	
  	
  	
  	
  for	
  (i	
  =	
  0;	
  i	
  <	
  backoff;	
  i++)	
  
	
  	
  	
  	
  	
  	
  snooze();	
  
	
  	
  	
  	
  backoff	
  =	
  (1ULL	
  <<	
  exp++);	
  
	
  	
  }

}	
  
TAS + backoff
Lockedalloc/free(10s)
10,000,000
20,000,000
30,000,000
40,000,000
50,000,000
60,000,000
Threads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Test and Set T&T&S TAS + EB
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
spinlock	
  global_lock	
  = UNLOCKED
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
spinlock	
  global_lock	
  = UNLOCKED
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
spinlock	
  global_lock	
  = UNLOCKED
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
spinlock	
  global_lock	
  = UNLOCKED
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
spinlock	
  global_lock	
  = LOCKED
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
spinlock	
  global_lock	
  = LOCKED
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
spinlock	
  global_lock	
  = LOCKED
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
spinlock	
  global_lock	
  = LOCKED
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
spinlock	
  global_lock	
  = LOCKED
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
void	
  lock(spinlock	
  *m)	
  {

	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

}
spinlock	
  global_lock	
  = LOCKED
A function is lock-free if at all times
at least one thread is
guaranteed to be making
progress [in the function].
(Herlihy & Shavit)
//	
  TODO:	
  make	
  this	
  safe	
  and	
  scalable

obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a	
  =	
  s-­‐>head;

	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  s-­‐>head	
  =	
  a-­‐>next;

	
  	
  return	
  a;

}	
  
//	
  TODO:	
  make	
  this	
  safe	
  and	
  scalable	
  
void	
  free(slab	
  *s,	
  obj	
  *o)	
  {	
  
	
  	
  o-­‐>next	
  =	
  s-­‐>head;

	
  	
  s-­‐>head	
  =	
  o;	
  
}
Non-Blocking
Algorithms
Compare-And-Swap
Compare-And-Swap
Cmpr and *
Old value
Destination
Address
Compare-And-Swap
≠
Return false
Old value
Destination
Address
Cmpr and *
Compare-And-Swap
Old value New value
≠
Return false
=
Destination
Address
Copy to *
Return true
Cmpr and *
Compare-And-Swap
Old value New value
≠
Return false
=
Destination
Address
Return true
Atomic
Copy to *Cmpr and *
Atomic i	
  =	
  i+1;
void	
  atomic_inc(int	
  *ptr)	
  {

	
  	
  int	
  i,	
  i_plus_one;

	
  	
  do	
  {	
  
	
  	
  	
  	
  i	
  =	
  *ptr;	
  
	
  	
  	
  	
  i_plus_one	
  =	
  i	
  +	
  1;

	
  	
  }	
  while	
  (!cas(i,	
  i_plus_one,	
  ptr));	
  


}
void	
  atomic_inc(int	
  *ptr)	
  {

	
  	
  int	
  i,	
  i_plus_one;

	
  	
  do	
  {	
  
	
  	
  	
  	
  i	
  =	
  *ptr;	
  
	
  	
  	
  	
  i_plus_one	
  =	
  i	
  +	
  1;

	
  	
  }	
  while	
  (!cas(i,	
  i_plus_one,	
  ptr));	
  


}
Atomic i	
  =	
  i+1;
void	
  atomic_inc(int	
  *ptr)	
  {

	
  	
  int	
  i,	
  i_plus_one;

	
  	
  do	
  {	
  
	
  	
  	
  	
  i	
  =	
  *ptr;	
  
	
  	
  	
  	
  i_plus_one	
  =	
  i	
  +	
  1;

	
  	
  }	
  while	
  (!cas(i,	
  i_plus_one,	
  ptr));	
  


}
Atomic i	
  =	
  i+1;
void	
  atomic_inc(int	
  *ptr)	
  {

	
  	
  int	
  i,	
  i_plus_one;

	
  	
  do	
  {	
  
	
  	
  	
  	
  i	
  =	
  *ptr;	
  
	
  	
  	
  	
  i_plus_one	
  =	
  i	
  +	
  1;

	
  	
  }	
  while	
  (!cas(i,	
  i_plus_one,	
  ptr));	
  


}
Atomic i	
  =	
  i+1;
void	
  atomic_inc_mod_32(int	
  *ptr)	
  {

	
  	
  int	
  i,	
  new_i;

	
  	
  do	
  {	
  
	
  	
  	
  	
  i	
  =	
  *ptr;	
  
	
  	
  	
  	
  new_i	
  =	
  i	
  +	
  1;	
  
	
  	
  	
  	
  new_i	
  =	
  new_i	
  %	
  32;

	
  	
  }	
  while	
  (!cas(i,	
  new_i,	
  ptr));

}
Atomic i	
  =	
  (i+1)	
  %	
  32;
TAS using CAS
void	
  tas_loop(spinlock	
  *m)	
  {

	
  	
  do	
  {	
  
	
  	
  	
  	
  ;

	
  	
  }	
  while	
  (!cas(UNLOCKED,	
  LOCKED,	
  m));	
  
}
Read/Modify/Write
void	
  atomic_inc_mod_32(int	
  *ptr)	
  {

	
  	
  int	
  i,	
  new_i;

	
  	
  do	
  {	
  
	
  	
  	
  	
  i	
  =	
  *ptr;	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  /*	
  Read	
  */	
  
	
  	
  	
  	
  new_i	
  =	
  fancy_function();	
  	
  	
  /*	
  Modify	
  */

	
  	
  }	
  while	
  (!cas(i,	
  new_i,	
  ptr));	
  /*	
  Write	
  */	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  

}
Read/Modify/Write
void	
  atomic_inc_mod_32(int	
  *ptr)	
  {

	
  	
  int	
  i,	
  new_i;

	
  	
  do	
  {	
  
	
  	
  	
  	
  i	
  =	
  *ptr;	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  /*	
  Read	
  */	
  
	
  	
  	
  	
  new_i	
  =	
  fancy_function();	
  	
  	
  /*	
  Modify	
  */

	
  	
  }	
  while	
  (!cas(i,	
  new_i,	
  ptr));	
  /*	
  Write	
  */	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  /*	
  (or	
  retry)	
  */

}
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head	
  ));

	
  	
  return	
  a;

}
slab head
A B …
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head	
  ));

	
  	
  return	
  a;

}
slab head
A B …
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head	
  ));

	
  	
  return	
  a;

}
A B …slab head
B …
slab head
A
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head	
  ));

	
  	
  return	
  a;

}
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(	
  	
  ,	
  	
  ,	
  	
  	
  	
  	
  	
  	
  	
  	
  ));

	
  	
  return	
  	
  a;

}
slab head
a
a b
Cmpr and *
&s->head
A B …
b
a
slab head
Cmpr and
Z
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(	
  	
  ,	
  	
  ,	
  	
  	
  	
  	
  	
  	
  	
  	
  ));

	
  	
  return	
  	
  a;

}
a
a b &s->head
b
a
slab head
Z A B
Cmpr and
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(	
  	
  ,	
  	
  ,	
  	
  	
  	
  	
  	
  	
  	
  	
  ));

	
  	
  return	
  	
  a;

}
a
a b &s->head
b
a
slab head
B …
Cmpr and
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(	
  	
  ,	
  	
  ,	
  	
  	
  	
  	
  	
  	
  	
  	
  ));

	
  	
  return	
  	
  a;

}
a
a b &s->head
b
a
void	
  free(slab	
  *s,	
  obj	
  *o)	
  {	
  
	
  	
  	
  	
  do	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  obj	
  *t	
  =	
  s-­‐>head;	
  
	
  	
  	
  	
  	
  	
  	
  	
  o-­‐>next	
  =	
  t;	
  
	
  	
  	
  	
  }	
  while	
  (!cas(t,	
  o,	
  &s-­‐>head));	
  
}
B …slab head
void	
  free(slab	
  *s,	
  obj	
  *o)	
  {	
  
	
  	
  	
  	
  do	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  obj	
  *t	
  =	
  s-­‐>head;	
  
	
  	
  	
  	
  	
  	
  	
  	
  o-­‐>next	
  =	
  t;	
  
	
  	
  	
  	
  }	
  while	
  (!cas(t,	
  o,	
  &s-­‐>head));	
  
}
slab head
A B …
A B Cslab head
A B Cslab head
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
A B Cslab head
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
A B Cslab head
A B C
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
slab head
A B C
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
slab head
A B C
some_object	
  =	
  allocate(&shared_slab);
slab head
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
A B C
some_object	
  =	
  allocate(&shared_slab);
slab head
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
B C
A
slab head
some_object	
  =	
  allocate(&shared_slab);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
B C
A
slab head
some_object	
  =	
  allocate(&shared_slab);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
B C
another_obj	
  =	
  allocate(&shared_slab);
A
slab head
some_object	
  =	
  allocate(&shared_slab);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
B C
another_obj	
  =	
  allocate(&shared_slab);
A
slab head
some_object	
  =	
  allocate(&shared_slab);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
C
A
B
slab head
another_obj	
  =	
  allocate(&shared_slab);
some_object	
  =	
  allocate(&shared_slab);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
C
A
B
slab head
another_obj	
  =	
  allocate(&shared_slab);
some_object	
  =	
  allocate(&shared_slab);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
B
C
A
slab head
another_obj	
  =	
  allocate(&shared_slab);
free(&shared_slab,	
  some_object);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
B
C
A
slab head
another_obj	
  =	
  allocate(&shared_slab);
free(&shared_slab,	
  some_object);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
B
A Cslab head
another_obj	
  =	
  allocate(&shared_slab);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
free(&shared_slab,	
  some_object);
B
A Cslab head
another_obj	
  =	
  allocate(&shared_slab);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
free(&shared_slab,	
  some_object);
B
A Cslab head
another_obj	
  =	
  allocate(&shared_slab);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
free(&shared_slab,	
  some_object);
B
A Cslab head
another_obj	
  =	
  allocate(&shared_slab);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
free(&shared_slab,	
  some_object);
free(&shared_slab,	
  some_object);
B
B Cslab head
A
another_obj	
  =	
  allocate(&shared_slab);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
free(&shared_slab,	
  some_object);
B
B Cslab head
A
another_obj	
  =	
  allocate(&shared_slab);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
free(&shared_slab,	
  some_object);
B
B Cslab head
A
another_obj	
  =	
  allocate(&shared_slab);
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
The ABA Problem
“A reference about to be modified by a CAS
changes from a to b and back to a again. As a
result, the CAS succeeds even though its effect on
the data structure has changed and no longer has
the desired effect.” —Herlihy & Shavit, p. 235
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  obj	
  *a,	
  *b;

	
  	
  do	
  {

	
  	
  	
  	
  a	
  =	
  s-­‐>head;

	
  	
  	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  	
  	
  b	
  =	
  a-­‐>next;

	
  	
  }	
  while	
  (!cas(a,	
  b,	
  &s-­‐>head));

	
  	
  return	
  a;

}
A B …slab head
166
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  slab	
  orig,	
  update;

	
  	
  do	
  {

	
  	
  	
  	
  orig.gen	
  =	
  s.gen;

	
  	
  	
  	
  orig.head	
  =	
  s.head;

	
  	
  	
  	
  if	
  (!orig.head)	
  return	
  NULL;	
  
	
  	
  	
  	
  update.gen	
  =	
  orig.gen	
  +	
  1;

	
  	
  	
  	
  update.head	
  =	
  orig.head-­‐>next;

	
  	
  }	
  while	
  (!dcas(&orig,	
  &update,	
  s));

	
  	
  return	
  orig.head;

}
A B …slab head
166
free(slab	
  *s,	
  obj	
  *o)	
  {	
  
	
  	
  	
  	
  do	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  obj	
  *t	
  =	
  s-­‐>head;	
  
	
  	
  	
  	
  	
  	
  	
  	
  o-­‐>next	
  =	
  t;	
  
	
  	
  	
  	
  }	
  while	
  (!cas(t,	
  o,	
  &s-­‐>head));	
  
}
obj	
  *allocate(slab	
  *s)	
  {

	
  	
  lock(&allocator_lock);

	
  	
  obj	
  *a	
  =	
  s-­‐>head;

	
  	
  if	
  (a	
  ==	
  NULL)	
  return	
  NULL;

	
  	
  s-­‐>head	
  =	
  a-­‐>next;

	
  	
  unlock(&allocator_lock);

	
  	
  return	
  a;

}	
  
void	
  free(slab	
  *s,	
  obj	
  *o)	
  {

	
  	
  lock(&allocator_lock);	
  
	
  	
  o-­‐>next	
  =	
  s-­‐>head;

	
  	
  s-­‐>head	
  =	
  o;

	
  	
  unlock(&allocator_lock);	
  
}
slab head
A B …
obj	
  *o	
  =	
  allocate(&shared_slab);
obj	
  *o	
  =	
  allocate(&shared_slab);
slab head
B …
obj	
  *o	
  =	
  allocate(&shared_slab);
obj	
  *o	
  =	
  allocate(&shared_slab);
A
A
slab head
B …
obj	
  *o	
  =	
  allocate(&shared_slab);
obj	
  *o	
  =	
  allocate(&shared_slab);
A
A
Memory barriers
 	
  lock(&allocator_lock);

	
  	
  obj	
  *a	
  =	
  s-­‐>head;

…
	
  	
  lock(&allocator_lock);

	
  	
  obj	
  *a	
  =	
  s-­‐>head;

…
 	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

	
  	
  obj	
  *a	
  =	
  s-­‐>head;

…
	
  	
  while	
  (atomic_tas(m,	
  LOCKED)	
  ==	
  LOCKED)	
  
	
  	
  	
  	
  snooze();

	
  	
  obj	
  *a	
  =	
  s-­‐>head;

…
 	
  LDREX	
  R5,	
  [m]	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  TAS:	
  fetch.	
  .	
  .	
  
	
  	
  STREXEQ	
  R5,	
  LOCKED,	
  [m]	
  ;	
  TAS:	
  .	
  .	
  .	
  and	
  set	
  
	
  	
  CMPEQ	
  R5,	
  #0	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  Did	
  we	
  succeed?
	
  LDR	
  R0,	
  [R1,	
  4]	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  a	
  =	
  s-­‐>head
	
  	
  BEQ	
  lock_done	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  Yes:	
  we	
  are	
  all	
  done

	
  	
  BL	
  snooze	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  No:	
  Call	
  snooze()…

	
  	
  B	
  lock_loop	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  	
  	
  	
  	
  …then	
  loop	
  again

lock_done:	
  
	
  	
  B	
  LR	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  return
;;;;	
  IN	
  lock()	
  
lock_loop:	
  
;;;;	
  IN	
  allocate()	
  
 	
  LDREX	
  R5,	
  [m]	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  TAS:	
  fetch.	
  .	
  .	
  
	
  	
  STREXEQ	
  R5,	
  LOCKED,	
  [m]	
  ;	
  TAS:	
  .	
  .	
  .	
  and	
  set	
  
	
  	
  CMPEQ	
  R5,	
  #0	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  Did	
  we	
  succeed?
	
  LDR	
  R0,	
  [R1,	
  4]	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  a	
  =	
  s-­‐>head
	
  	
  BEQ	
  lock_done	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  Yes:	
  we	
  are	
  all	
  done

	
  	
  BL	
  snooze	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  No:	
  Call	
  snooze()…

	
  	
  B	
  lock_loop	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  	
  	
  	
  	
  …then	
  loop	
  again

lock_done:	
  
	
  	
  B	
  LR	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  return
;;;;	
  IN	
  allocate()	
  
;;;;	
  IN	
  lock()	
  
lock_loop:	
  
 LDR	
  R0,	
  [R1,	
  4]	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  a	
  =	
  s-­‐>head
	
  	
  BEQ	
  lock_done	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  Yes:	
  we	
  are	
  all	
  done

	
  	
  BL	
  snooze	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  No:	
  Call	
  snooze()…

	
  	
  B	
  lock_loop	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  	
  	
  	
  	
  …then	
  loop	
  again

lock_done:	
  
	
  	
  B	
  LR	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  return
;;;;	
  IN	
  allocate()	
  
	
  	
  LDREX	
  R5,	
  [m]	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  TAS:	
  fetch.	
  .	
  .	
  
	
  	
  STREXEQ	
  R5,	
  LOCKED,	
  [m]	
  ;	
  TAS:	
  .	
  .	
  .	
  and	
  set	
  
	
  	
  CMPEQ	
  R5,	
  #0	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  Did	
  we	
  succeed?
;;;;	
  IN	
  lock()	
  
lock_loop:	
  
McKenney , p. 504
McKenney , p. 504
McKenney , p. 504
McKenney , p. 504
 	
  LDREX	
  R5,	
  [m]	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  TAS:	
  fetch.	
  .	
  .	
  
	
  	
  STREXEQ	
  R5,	
  LOCKED,	
  [m]	
  ;	
  TAS:	
  .	
  .	
  .	
  and	
  set	
  
	
  	
  CMPEQ	
  R5,	
  #0	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  Did	
  we	
  succeed?
	
  LDR	
  R0,	
  [R1,	
  4]	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  a	
  =	
  s-­‐>head
	
  	
  BEQ	
  lock_done	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  Yes:	
  we	
  are	
  all	
  done

	
  	
  BL	
  snooze	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  No:	
  Call	
  snooze()…

	
  	
  B	
  lock_loop	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  	
  	
  	
  	
  …then	
  loop	
  again

lock_done:	
  
	
  	
  B	
  LR	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  return
;;;;	
  IN	
  allocate()	
  
;;;;	
  IN	
  lock()	
  
lock_loop:	
  
 	
  LDREX	
  R5,	
  [m]	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  TAS:	
  fetch.	
  .	
  .	
  
	
  	
  STREXEQ	
  R5,	
  LOCKED,	
  [m]	
  ;	
  TAS:	
  .	
  .	
  .	
  and	
  set	
  
	
  	
  CMPEQ	
  R5,	
  #0	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  Did	
  we	
  succeed?
	
  LDR	
  R0,	
  [R1,	
  4]	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  a	
  =	
  s-­‐>head
	
  	
  BEQ	
  lock_done	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  Yes:	
  we	
  are	
  all	
  done

	
  	
  BL	
  snooze	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  No:	
  Call	
  snooze()…

	
  	
  B	
  lock_loop	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  	
  	
  	
  	
  …then	
  loop	
  again

lock_done:	
  
	
  	
  B	
  LR	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  return
;;;;	
  IN	
  allocate()	
  
;;;;	
  IN	
  lock()	
  
lock_loop:	
  
 	
  obj	
  *a	
  =	
  s-­‐>head;	
  
	
  	
  lock(&allocator_lock);

…
	
  	
  obj	
  *a	
  =	
  s-­‐>head;

	
  	
  lock(&allocator_lock);

…
 	
  lock(&allocator_lock);

	
  	
  obj	
  *a	
  =	
  s-­‐>head;

…
	
  	
  lock(&allocator_lock);

	
  	
  obj	
  *a	
  =	
  s-­‐>head;

…
 	
  lock(&allocator_lock);	
  
	
  	
  <	
  -­‐	
  -­‐	
  -­‐	
  -­‐	
  -­‐	
  -­‐	
  -­‐	
  -­‐	
  -­‐	
  -­‐>

	
  	
  obj	
  *a	
  =	
  s-­‐>head;

…
	
  	
  lock(&allocator_lock);	
  
	
  	
  <	
  -­‐	
  -­‐	
  -­‐	
  -­‐	
  -­‐	
  -­‐	
  -­‐	
  -­‐	
  -­‐	
  -­‐>

	
  	
  obj	
  *a	
  =	
  s-­‐>head;

…
 	
  LDREX	
  R5,	
  [m]	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  TAS:	
  fetch.	
  .	
  .	
  
	
  	
  STREXEQ	
  R5,	
  LOCKED,	
  [m]	
  ;	
  TAS:	
  .	
  .	
  .	
  and	
  set	
  
	
  	
  CMPEQ	
  R5,	
  #0	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  Did	
  we	
  succeed?
	
  	
  BEQ	
  lock_done	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  Yes:	
  we	
  are	
  all	
  done

	
  	
  BL	
  snooze	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  No:	
  Call	
  snooze()…

	
  	
  B	
  lock_loop	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  	
  	
  	
  	
  …then	
  loop	
  again

lock_done:	
  
	
  	
  DMB	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  Ensure	
  all	
  previous	
  reads	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  have	
  been	
  completed	
  
	
  	
  B	
  LR	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  return
;;;;	
  IN	
  unlock()	
  
	
  	
  MOV	
  R0,	
  UNLOCKED	
  
	
  	
  DMB	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  Ensure	
  all	
  previous	
  reads	
  have	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ;	
  been	
  completed	
  
	
  	
  STR	
  R0,	
  LR
;;;;	
  IN	
  lock()	
  
lock_loop:	
  
nathan~$	
  cat	
  /proc/cpuinfo	
  |	
  grep	
  "physical.*0"	
  |	
  wc	
  -­‐l	
  
16	
  
nathan~$	
  cat	
  /proc/cpuinfo	
  |	
  grep	
  "model	
  name"	
  |	
  uniq	
  
model	
  name	
  :	
  Intel(R)	
  Xeon(R)	
  CPU	
  E5-­‐2690	
  0	
  @	
  2.90GHz
Allocator performance
MillionsofAlloc/free

pairs/sec
10
20
30
40
50
60
Threads
1
20.56822.392
50.52951.23452.721
T&S T&S-EB T&T&S CAS
pthread_mutex
Allocator Throughput
MillionsofAlloc/free

pairs/sec
10
20
30
40
50
60
Threads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
TAS T&T&S TAS + EB
Concurrent Allocator pthread
Allocator Throughput
Allocator latency
Allocator latency
Threads
CPUCycles
Allocator latency
Threads
CPUCycles
Allocator latency
Threads
CPUCycles
Allocator latency
Threads
CPUCycles
https://github.com/fastly/uslab
The lyf so short,
the CAS so longe to lerne
• Cache coherency and NUMA architecture
• Transactional memory
#thoughtleadership
a safe race?
When is a race
“lock-free programming is
hard; let’s go ride bikes”?
“lock-free programming is
hard; let’s go ride bikes”?
• high-level performance necessitates an
understanding of low level performance
“lock-free programming is
hard; let’s go ride bikes”?
• high-level performance necessitates an
understanding of low level performance
• your computer is a distributed system
“lock-free programming is
hard; let’s go ride bikes”?
• high-level performance necessitates an
understanding of low level performance
• your computer is a distributed system
• (optional third answer: it’s real neato)
Come see us at the booth!
Nathan Taylor | nathan.dijkstracula.net | @dijkstracula
Thanks
credits, code, and additional material at
https://github.com/dijkstracula/Surge2015/

Weitere ähnliche Inhalte

Was ist angesagt?

Extend R with Rcpp!!!
Extend R with Rcpp!!!Extend R with Rcpp!!!
Extend R with Rcpp!!!mickey24
 
Clojure Intro
Clojure IntroClojure Intro
Clojure Introthnetos
 
Java Concurrency Gotchas
Java Concurrency GotchasJava Concurrency Gotchas
Java Concurrency GotchasAlex Miller
 
Beginning direct3d gameprogrammingcpp02_20160324_jintaeks
Beginning direct3d gameprogrammingcpp02_20160324_jintaeksBeginning direct3d gameprogrammingcpp02_20160324_jintaeks
Beginning direct3d gameprogrammingcpp02_20160324_jintaeksJinTaek Seo
 
Understanding the Disruptor
Understanding the DisruptorUnderstanding the Disruptor
Understanding the DisruptorTrisha Gee
 
CppConcurrencyInAction - Chapter07
CppConcurrencyInAction - Chapter07CppConcurrencyInAction - Chapter07
CppConcurrencyInAction - Chapter07DooSeon Choi
 
20100712-OTcl Command -- Getting Started
20100712-OTcl Command -- Getting Started20100712-OTcl Command -- Getting Started
20100712-OTcl Command -- Getting StartedTeerawat Issariyakul
 
Predictably
PredictablyPredictably
Predictablyztellman
 
EdSketch: Execution-Driven Sketching for Java
EdSketch: Execution-Driven Sketching for JavaEdSketch: Execution-Driven Sketching for Java
EdSketch: Execution-Driven Sketching for JavaLisa Hua
 
zkStudyClub: PLONKUP & Reinforced Concrete [Luke Pearson, Joshua Fitzgerald, ...
zkStudyClub: PLONKUP & Reinforced Concrete [Luke Pearson, Joshua Fitzgerald, ...zkStudyClub: PLONKUP & Reinforced Concrete [Luke Pearson, Joshua Fitzgerald, ...
zkStudyClub: PLONKUP & Reinforced Concrete [Luke Pearson, Joshua Fitzgerald, ...Alex Pruden
 
Turtle Graphics in Groovy
Turtle Graphics in GroovyTurtle Graphics in Groovy
Turtle Graphics in GroovyJim Driscoll
 
Deuce STM - CMP'09
Deuce STM - CMP'09Deuce STM - CMP'09
Deuce STM - CMP'09Guy Korland
 
Modern c++ Memory Management
Modern c++ Memory ManagementModern c++ Memory Management
Modern c++ Memory ManagementAlan Uthoff
 
Next Generation Indexes For Big Data Engineering (ODSC East 2018)
Next Generation Indexes For Big Data Engineering (ODSC East 2018)Next Generation Indexes For Big Data Engineering (ODSC East 2018)
Next Generation Indexes For Big Data Engineering (ODSC East 2018)Daniel Lemire
 
Actor Concurrency
Actor ConcurrencyActor Concurrency
Actor ConcurrencyAlex Miller
 
NS2: Binding C++ and OTcl variables
NS2: Binding C++ and OTcl variablesNS2: Binding C++ and OTcl variables
NS2: Binding C++ and OTcl variablesTeerawat Issariyakul
 

Was ist angesagt? (20)

Extend R with Rcpp!!!
Extend R with Rcpp!!!Extend R with Rcpp!!!
Extend R with Rcpp!!!
 
Clojure Intro
Clojure IntroClojure Intro
Clojure Intro
 
Java Concurrency Gotchas
Java Concurrency GotchasJava Concurrency Gotchas
Java Concurrency Gotchas
 
Beginning direct3d gameprogrammingcpp02_20160324_jintaeks
Beginning direct3d gameprogrammingcpp02_20160324_jintaeksBeginning direct3d gameprogrammingcpp02_20160324_jintaeks
Beginning direct3d gameprogrammingcpp02_20160324_jintaeks
 
Understanding the Disruptor
Understanding the DisruptorUnderstanding the Disruptor
Understanding the Disruptor
 
Pattern Matching in Java 14
Pattern Matching in Java 14Pattern Matching in Java 14
Pattern Matching in Java 14
 
Disruptor
DisruptorDisruptor
Disruptor
 
CppConcurrencyInAction - Chapter07
CppConcurrencyInAction - Chapter07CppConcurrencyInAction - Chapter07
CppConcurrencyInAction - Chapter07
 
20100712-OTcl Command -- Getting Started
20100712-OTcl Command -- Getting Started20100712-OTcl Command -- Getting Started
20100712-OTcl Command -- Getting Started
 
Predictably
PredictablyPredictably
Predictably
 
EdSketch: Execution-Driven Sketching for Java
EdSketch: Execution-Driven Sketching for JavaEdSketch: Execution-Driven Sketching for Java
EdSketch: Execution-Driven Sketching for Java
 
zkStudyClub: PLONKUP & Reinforced Concrete [Luke Pearson, Joshua Fitzgerald, ...
zkStudyClub: PLONKUP & Reinforced Concrete [Luke Pearson, Joshua Fitzgerald, ...zkStudyClub: PLONKUP & Reinforced Concrete [Luke Pearson, Joshua Fitzgerald, ...
zkStudyClub: PLONKUP & Reinforced Concrete [Luke Pearson, Joshua Fitzgerald, ...
 
Ds 2 cycle
Ds 2 cycleDs 2 cycle
Ds 2 cycle
 
Turtle Graphics in Groovy
Turtle Graphics in GroovyTurtle Graphics in Groovy
Turtle Graphics in Groovy
 
Deuce STM - CMP'09
Deuce STM - CMP'09Deuce STM - CMP'09
Deuce STM - CMP'09
 
WOTC_Import
WOTC_ImportWOTC_Import
WOTC_Import
 
Modern c++ Memory Management
Modern c++ Memory ManagementModern c++ Memory Management
Modern c++ Memory Management
 
Next Generation Indexes For Big Data Engineering (ODSC East 2018)
Next Generation Indexes For Big Data Engineering (ODSC East 2018)Next Generation Indexes For Big Data Engineering (ODSC East 2018)
Next Generation Indexes For Big Data Engineering (ODSC East 2018)
 
Actor Concurrency
Actor ConcurrencyActor Concurrency
Actor Concurrency
 
NS2: Binding C++ and OTcl variables
NS2: Binding C++ and OTcl variablesNS2: Binding C++ and OTcl variables
NS2: Binding C++ and OTcl variables
 

Ähnlich wie Racing To Win: Using Race Conditions to Build Correct and Concurrent Software

Agile Iphone Development
Agile Iphone DevelopmentAgile Iphone Development
Agile Iphone DevelopmentGiordano Scalzo
 
The Future of JVM Languages
The Future of JVM Languages The Future of JVM Languages
The Future of JVM Languages VictorSzoltysek
 
iOS Development with Blocks
iOS Development with BlocksiOS Development with Blocks
iOS Development with BlocksJeff Kelley
 
Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)HamletDRC
 
AST Transformations
AST TransformationsAST Transformations
AST TransformationsHamletDRC
 
Parallele Suche in grossen Graphen mit Heuristiken und Caches
Parallele Suche in grossen Graphen mit Heuristiken und CachesParallele Suche in grossen Graphen mit Heuristiken und Caches
Parallele Suche in grossen Graphen mit Heuristiken und CachesJAVAPRO
 
The State of Lightweight Threads for the JVM
The State of Lightweight Threads for the JVMThe State of Lightweight Threads for the JVM
The State of Lightweight Threads for the JVMVolkan Yazıcı
 
Nicety of java 8 multithreading for advanced, Max Voronoy
Nicety of java 8 multithreading for advanced, Max VoronoyNicety of java 8 multithreading for advanced, Max Voronoy
Nicety of java 8 multithreading for advanced, Max VoronoySigma Software
 
Kotlin coroutine - the next step for RxJava developer?
Kotlin coroutine - the next step for RxJava developer?Kotlin coroutine - the next step for RxJava developer?
Kotlin coroutine - the next step for RxJava developer?Artur Latoszewski
 
Blocks & GCD
Blocks & GCDBlocks & GCD
Blocks & GCDrsebbe
 
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017 Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017 Codemotion
 
Openstack taskflow 簡介
Openstack taskflow 簡介Openstack taskflow 簡介
Openstack taskflow 簡介kao kuo-tung
 
Lock free algorithms
Lock free algorithmsLock free algorithms
Lock free algorithmsPan Ip
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokusHamletDRC
 
Bdd for ios with kiwi
Bdd for ios with kiwiBdd for ios with kiwi
Bdd for ios with kiwiGnat
 
Ast transformations
Ast transformationsAst transformations
Ast transformationsHamletDRC
 
Parsing with Perl6 Grammars
Parsing with Perl6 GrammarsParsing with Perl6 Grammars
Parsing with Perl6 Grammarsabrummett
 
Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017Sunghyouk Bae
 
The Art of Java Type Patterns
The Art of Java Type PatternsThe Art of Java Type Patterns
The Art of Java Type PatternsSimon Ritter
 

Ähnlich wie Racing To Win: Using Race Conditions to Build Correct and Concurrent Software (20)

Agile Iphone Development
Agile Iphone DevelopmentAgile Iphone Development
Agile Iphone Development
 
The Future of JVM Languages
The Future of JVM Languages The Future of JVM Languages
The Future of JVM Languages
 
iOS Development with Blocks
iOS Development with BlocksiOS Development with Blocks
iOS Development with Blocks
 
Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)
 
AST Transformations
AST TransformationsAST Transformations
AST Transformations
 
Parallele Suche in grossen Graphen mit Heuristiken und Caches
Parallele Suche in grossen Graphen mit Heuristiken und CachesParallele Suche in grossen Graphen mit Heuristiken und Caches
Parallele Suche in grossen Graphen mit Heuristiken und Caches
 
The State of Lightweight Threads for the JVM
The State of Lightweight Threads for the JVMThe State of Lightweight Threads for the JVM
The State of Lightweight Threads for the JVM
 
Nicety of java 8 multithreading for advanced, Max Voronoy
Nicety of java 8 multithreading for advanced, Max VoronoyNicety of java 8 multithreading for advanced, Max Voronoy
Nicety of java 8 multithreading for advanced, Max Voronoy
 
Nicety of Java 8 Multithreading
Nicety of Java 8 MultithreadingNicety of Java 8 Multithreading
Nicety of Java 8 Multithreading
 
Kotlin coroutine - the next step for RxJava developer?
Kotlin coroutine - the next step for RxJava developer?Kotlin coroutine - the next step for RxJava developer?
Kotlin coroutine - the next step for RxJava developer?
 
Blocks & GCD
Blocks & GCDBlocks & GCD
Blocks & GCD
 
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017 Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
 
Openstack taskflow 簡介
Openstack taskflow 簡介Openstack taskflow 簡介
Openstack taskflow 簡介
 
Lock free algorithms
Lock free algorithmsLock free algorithms
Lock free algorithms
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
 
Bdd for ios with kiwi
Bdd for ios with kiwiBdd for ios with kiwi
Bdd for ios with kiwi
 
Ast transformations
Ast transformationsAst transformations
Ast transformations
 
Parsing with Perl6 Grammars
Parsing with Perl6 GrammarsParsing with Perl6 Grammars
Parsing with Perl6 Grammars
 
Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017
 
The Art of Java Type Patterns
The Art of Java Type PatternsThe Art of Java Type Patterns
The Art of Java Type Patterns
 

Mehr von Fastly

Revisiting HTTP/2
Revisiting HTTP/2Revisiting HTTP/2
Revisiting HTTP/2Fastly
 
Altitude San Francisco 2018: Preparing for Video Streaming Events at Scale
Altitude San Francisco 2018: Preparing for Video Streaming Events at ScaleAltitude San Francisco 2018: Preparing for Video Streaming Events at Scale
Altitude San Francisco 2018: Preparing for Video Streaming Events at ScaleFastly
 
Altitude San Francisco 2018: Building the Souther Hemisphere of the Internet
Altitude San Francisco 2018: Building the Souther Hemisphere of the InternetAltitude San Francisco 2018: Building the Souther Hemisphere of the Internet
Altitude San Francisco 2018: Building the Souther Hemisphere of the InternetFastly
 
Altitude San Francisco 2018: The World Cup Stream
Altitude San Francisco 2018: The World Cup StreamAltitude San Francisco 2018: The World Cup Stream
Altitude San Francisco 2018: The World Cup StreamFastly
 
Altitude San Francisco 2018: We Own Our Destiny
Altitude San Francisco 2018: We Own Our DestinyAltitude San Francisco 2018: We Own Our Destiny
Altitude San Francisco 2018: We Own Our DestinyFastly
 
Altitude San Francisco 2018: Scale and Stability at the Edge with 1.4 Billion...
Altitude San Francisco 2018: Scale and Stability at the Edge with 1.4 Billion...Altitude San Francisco 2018: Scale and Stability at the Edge with 1.4 Billion...
Altitude San Francisco 2018: Scale and Stability at the Edge with 1.4 Billion...Fastly
 
Altitude San Francisco 2018: Moving Off the Monolith: A Seamless Migration
Altitude San Francisco 2018: Moving Off the Monolith: A Seamless MigrationAltitude San Francisco 2018: Moving Off the Monolith: A Seamless Migration
Altitude San Francisco 2018: Moving Off the Monolith: A Seamless MigrationFastly
 
Altitude San Francisco 2018: Bringing TLS to GitHub Pages
Altitude San Francisco 2018: Bringing TLS to GitHub PagesAltitude San Francisco 2018: Bringing TLS to GitHub Pages
Altitude San Francisco 2018: Bringing TLS to GitHub PagesFastly
 
Altitude San Francisco 2018: HTTP Invalidation Workshop
Altitude San Francisco 2018: HTTP Invalidation WorkshopAltitude San Francisco 2018: HTTP Invalidation Workshop
Altitude San Francisco 2018: HTTP Invalidation WorkshopFastly
 
Altitude San Francisco 2018: HTTP/2 Tales: Discovery and Woe
Altitude San Francisco 2018: HTTP/2 Tales: Discovery and WoeAltitude San Francisco 2018: HTTP/2 Tales: Discovery and Woe
Altitude San Francisco 2018: HTTP/2 Tales: Discovery and WoeFastly
 
Altitude San Francisco 2018: How Magento moved to the cloud while maintaining...
Altitude San Francisco 2018: How Magento moved to the cloud while maintaining...Altitude San Francisco 2018: How Magento moved to the cloud while maintaining...
Altitude San Francisco 2018: How Magento moved to the cloud while maintaining...Fastly
 
Altitude San Francisco 2018: Scaling Ethereum to 10B requests per day
Altitude San Francisco 2018: Scaling Ethereum to 10B requests per dayAltitude San Francisco 2018: Scaling Ethereum to 10B requests per day
Altitude San Francisco 2018: Scaling Ethereum to 10B requests per dayFastly
 
Altitude San Francisco 2018: Authentication at the Edge
Altitude San Francisco 2018: Authentication at the EdgeAltitude San Francisco 2018: Authentication at the Edge
Altitude San Francisco 2018: Authentication at the EdgeFastly
 
Altitude San Francisco 2018: WebAssembly Tools & Applications
Altitude San Francisco 2018: WebAssembly Tools & ApplicationsAltitude San Francisco 2018: WebAssembly Tools & Applications
Altitude San Francisco 2018: WebAssembly Tools & ApplicationsFastly
 
Altitude San Francisco 2018: Testing with Fastly Workshop
Altitude San Francisco 2018: Testing with Fastly WorkshopAltitude San Francisco 2018: Testing with Fastly Workshop
Altitude San Francisco 2018: Testing with Fastly WorkshopFastly
 
Altitude San Francisco 2018: Fastly Purge Control at the USA TODAY NETWORK
Altitude San Francisco 2018: Fastly Purge Control at the USA TODAY NETWORKAltitude San Francisco 2018: Fastly Purge Control at the USA TODAY NETWORK
Altitude San Francisco 2018: Fastly Purge Control at the USA TODAY NETWORKFastly
 
Altitude San Francisco 2018: WAF Workshop
Altitude San Francisco 2018: WAF WorkshopAltitude San Francisco 2018: WAF Workshop
Altitude San Francisco 2018: WAF WorkshopFastly
 
Altitude San Francisco 2018: Logging at the Edge
Altitude San Francisco 2018: Logging at the Edge Altitude San Francisco 2018: Logging at the Edge
Altitude San Francisco 2018: Logging at the Edge Fastly
 
Altitude San Francisco 2018: Video Workshop Docs
Altitude San Francisco 2018: Video Workshop DocsAltitude San Francisco 2018: Video Workshop Docs
Altitude San Francisco 2018: Video Workshop DocsFastly
 
Altitude San Francisco 2018: Programming the Edge
Altitude San Francisco 2018: Programming the EdgeAltitude San Francisco 2018: Programming the Edge
Altitude San Francisco 2018: Programming the EdgeFastly
 

Mehr von Fastly (20)

Revisiting HTTP/2
Revisiting HTTP/2Revisiting HTTP/2
Revisiting HTTP/2
 
Altitude San Francisco 2018: Preparing for Video Streaming Events at Scale
Altitude San Francisco 2018: Preparing for Video Streaming Events at ScaleAltitude San Francisco 2018: Preparing for Video Streaming Events at Scale
Altitude San Francisco 2018: Preparing for Video Streaming Events at Scale
 
Altitude San Francisco 2018: Building the Souther Hemisphere of the Internet
Altitude San Francisco 2018: Building the Souther Hemisphere of the InternetAltitude San Francisco 2018: Building the Souther Hemisphere of the Internet
Altitude San Francisco 2018: Building the Souther Hemisphere of the Internet
 
Altitude San Francisco 2018: The World Cup Stream
Altitude San Francisco 2018: The World Cup StreamAltitude San Francisco 2018: The World Cup Stream
Altitude San Francisco 2018: The World Cup Stream
 
Altitude San Francisco 2018: We Own Our Destiny
Altitude San Francisco 2018: We Own Our DestinyAltitude San Francisco 2018: We Own Our Destiny
Altitude San Francisco 2018: We Own Our Destiny
 
Altitude San Francisco 2018: Scale and Stability at the Edge with 1.4 Billion...
Altitude San Francisco 2018: Scale and Stability at the Edge with 1.4 Billion...Altitude San Francisco 2018: Scale and Stability at the Edge with 1.4 Billion...
Altitude San Francisco 2018: Scale and Stability at the Edge with 1.4 Billion...
 
Altitude San Francisco 2018: Moving Off the Monolith: A Seamless Migration
Altitude San Francisco 2018: Moving Off the Monolith: A Seamless MigrationAltitude San Francisco 2018: Moving Off the Monolith: A Seamless Migration
Altitude San Francisco 2018: Moving Off the Monolith: A Seamless Migration
 
Altitude San Francisco 2018: Bringing TLS to GitHub Pages
Altitude San Francisco 2018: Bringing TLS to GitHub PagesAltitude San Francisco 2018: Bringing TLS to GitHub Pages
Altitude San Francisco 2018: Bringing TLS to GitHub Pages
 
Altitude San Francisco 2018: HTTP Invalidation Workshop
Altitude San Francisco 2018: HTTP Invalidation WorkshopAltitude San Francisco 2018: HTTP Invalidation Workshop
Altitude San Francisco 2018: HTTP Invalidation Workshop
 
Altitude San Francisco 2018: HTTP/2 Tales: Discovery and Woe
Altitude San Francisco 2018: HTTP/2 Tales: Discovery and WoeAltitude San Francisco 2018: HTTP/2 Tales: Discovery and Woe
Altitude San Francisco 2018: HTTP/2 Tales: Discovery and Woe
 
Altitude San Francisco 2018: How Magento moved to the cloud while maintaining...
Altitude San Francisco 2018: How Magento moved to the cloud while maintaining...Altitude San Francisco 2018: How Magento moved to the cloud while maintaining...
Altitude San Francisco 2018: How Magento moved to the cloud while maintaining...
 
Altitude San Francisco 2018: Scaling Ethereum to 10B requests per day
Altitude San Francisco 2018: Scaling Ethereum to 10B requests per dayAltitude San Francisco 2018: Scaling Ethereum to 10B requests per day
Altitude San Francisco 2018: Scaling Ethereum to 10B requests per day
 
Altitude San Francisco 2018: Authentication at the Edge
Altitude San Francisco 2018: Authentication at the EdgeAltitude San Francisco 2018: Authentication at the Edge
Altitude San Francisco 2018: Authentication at the Edge
 
Altitude San Francisco 2018: WebAssembly Tools & Applications
Altitude San Francisco 2018: WebAssembly Tools & ApplicationsAltitude San Francisco 2018: WebAssembly Tools & Applications
Altitude San Francisco 2018: WebAssembly Tools & Applications
 
Altitude San Francisco 2018: Testing with Fastly Workshop
Altitude San Francisco 2018: Testing with Fastly WorkshopAltitude San Francisco 2018: Testing with Fastly Workshop
Altitude San Francisco 2018: Testing with Fastly Workshop
 
Altitude San Francisco 2018: Fastly Purge Control at the USA TODAY NETWORK
Altitude San Francisco 2018: Fastly Purge Control at the USA TODAY NETWORKAltitude San Francisco 2018: Fastly Purge Control at the USA TODAY NETWORK
Altitude San Francisco 2018: Fastly Purge Control at the USA TODAY NETWORK
 
Altitude San Francisco 2018: WAF Workshop
Altitude San Francisco 2018: WAF WorkshopAltitude San Francisco 2018: WAF Workshop
Altitude San Francisco 2018: WAF Workshop
 
Altitude San Francisco 2018: Logging at the Edge
Altitude San Francisco 2018: Logging at the Edge Altitude San Francisco 2018: Logging at the Edge
Altitude San Francisco 2018: Logging at the Edge
 
Altitude San Francisco 2018: Video Workshop Docs
Altitude San Francisco 2018: Video Workshop DocsAltitude San Francisco 2018: Video Workshop Docs
Altitude San Francisco 2018: Video Workshop Docs
 
Altitude San Francisco 2018: Programming the Edge
Altitude San Francisco 2018: Programming the EdgeAltitude San Francisco 2018: Programming the Edge
Altitude San Francisco 2018: Programming the Edge
 

Kürzlich hochgeladen

AWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptxAWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptxellan12
 
Russian Call girl in Ajman +971563133746 Ajman Call girl Service
Russian Call girl in Ajman +971563133746 Ajman Call girl ServiceRussian Call girl in Ajman +971563133746 Ajman Call girl Service
Russian Call girl in Ajman +971563133746 Ajman Call girl Servicegwenoracqe6
 
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night StandHot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Standkumarajju5765
 
Call Girls in Mayur Vihar ✔️ 9711199171 ✔️ Delhi ✔️ Enjoy Call Girls With Our...
Call Girls in Mayur Vihar ✔️ 9711199171 ✔️ Delhi ✔️ Enjoy Call Girls With Our...Call Girls in Mayur Vihar ✔️ 9711199171 ✔️ Delhi ✔️ Enjoy Call Girls With Our...
Call Girls in Mayur Vihar ✔️ 9711199171 ✔️ Delhi ✔️ Enjoy Call Girls With Our...sonatiwari757
 
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip CallDelhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Callshivangimorya083
 
GDG Cloud Southlake 32: Kyle Hettinger: Demystifying the Dark Web
GDG Cloud Southlake 32: Kyle Hettinger: Demystifying the Dark WebGDG Cloud Southlake 32: Kyle Hettinger: Demystifying the Dark Web
GDG Cloud Southlake 32: Kyle Hettinger: Demystifying the Dark WebJames Anderson
 
Pune Airport ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready...
Pune Airport ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready...Pune Airport ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready...
Pune Airport ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready...tanu pandey
 
Russian Call girls in Dubai +971563133746 Dubai Call girls
Russian  Call girls in Dubai +971563133746 Dubai  Call girlsRussian  Call girls in Dubai +971563133746 Dubai  Call girls
Russian Call girls in Dubai +971563133746 Dubai Call girlsstephieert
 
Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
Top Rated Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
Top Rated  Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...Top Rated  Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
Top Rated Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...Call Girls in Nagpur High Profile
 
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...Neha Pandey
 
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRLLucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRLimonikaupta
 
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779Delhi Call girls
 
FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607
FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607
FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607dollysharma2066
 
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girl
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call GirlVIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girl
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girladitipandeya
 

Kürzlich hochgeladen (20)

AWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptxAWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptx
 
Russian Call girl in Ajman +971563133746 Ajman Call girl Service
Russian Call girl in Ajman +971563133746 Ajman Call girl ServiceRussian Call girl in Ajman +971563133746 Ajman Call girl Service
Russian Call girl in Ajman +971563133746 Ajman Call girl Service
 
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
 
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night StandHot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
 
Call Girls in Mayur Vihar ✔️ 9711199171 ✔️ Delhi ✔️ Enjoy Call Girls With Our...
Call Girls in Mayur Vihar ✔️ 9711199171 ✔️ Delhi ✔️ Enjoy Call Girls With Our...Call Girls in Mayur Vihar ✔️ 9711199171 ✔️ Delhi ✔️ Enjoy Call Girls With Our...
Call Girls in Mayur Vihar ✔️ 9711199171 ✔️ Delhi ✔️ Enjoy Call Girls With Our...
 
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip CallDelhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
 
GDG Cloud Southlake 32: Kyle Hettinger: Demystifying the Dark Web
GDG Cloud Southlake 32: Kyle Hettinger: Demystifying the Dark WebGDG Cloud Southlake 32: Kyle Hettinger: Demystifying the Dark Web
GDG Cloud Southlake 32: Kyle Hettinger: Demystifying the Dark Web
 
Pune Airport ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready...
Pune Airport ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready...Pune Airport ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready...
Pune Airport ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready...
 
Russian Call girls in Dubai +971563133746 Dubai Call girls
Russian  Call girls in Dubai +971563133746 Dubai  Call girlsRussian  Call girls in Dubai +971563133746 Dubai  Call girls
Russian Call girls in Dubai +971563133746 Dubai Call girls
 
Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝
 
Top Rated Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
Top Rated  Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...Top Rated  Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
Top Rated Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
 
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
 
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
 
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRLLucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
 
Call Girls In South Ex 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SERVICE
Call Girls In South Ex 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SERVICECall Girls In South Ex 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SERVICE
Call Girls In South Ex 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SERVICE
 
Rohini Sector 6 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
Rohini Sector 6 Call Girls Delhi 9999965857 @Sabina Saikh No AdvanceRohini Sector 6 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
Rohini Sector 6 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
 
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
Best VIP Call Girls Noida Sector 75 Call Me: 8448380779
 
FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607
FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607
FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607
 
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girl
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call GirlVIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girl
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girl
 
Rohini Sector 26 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
Rohini Sector 26 Call Girls Delhi 9999965857 @Sabina Saikh No AdvanceRohini Sector 26 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
Rohini Sector 26 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
 

Racing To Win: Using Race Conditions to Build Correct and Concurrent Software

  • 1. Racing To Win Using Race Conditions to Build Correct & Concurrent Software Nathan Taylor | nathan.dijkstracula.net | @dijkstracula
  • 2. Racing To Win Using Race Conditions to Build Correct & Concurrent Software Nathan Taylor | nathan.dijkstracula.net | @dijkstracula
  • 3. Hi, I’m Nathan. ( @dijkstracula )
  • 5.
  • 9.
  • 10.
  • 11.
  • 12.
  • 14. Cache node Process A stack heap text Process B stack heap text Process C stack heap text
  • 15. Cache node Process A stack heap text Process B stack heap text Process C stack heap text
  • 16. A Persistent, Shared- State Memory Allocator Cache node Process A stack heap text Process B stack heap text Process C stack heap text uSlab
  • 18. Slab allocation Object Object Object Object Object Object Object Object
  • 19. Object Object Object Object Object Object Object Object
  • 23. s_free(              ); s_free(              ); s_free(              ); Object ObjectObject Object Object Object Object Object
  • 24. Object Object Object Object Object Object Object Object
  • 25. Object Object Object Object Object Object Object Object
  • 26. Allocation Protocol • An request to allocate is followed by a response containing an object • A request to free is followed by a response after the supplied object has been released
 
 • Allocation requests must not respond with an already- allocated object • A free request must not release an already-unallocated object
  • 28. An Execution History void foo() {
 obj *a = s_alloc();
 s_free(a);
 …
 }
  • 29. An Execution History Time void foo() {
 obj *a = s_alloc();
 s_free(a);
 …
 } A(allocate request) B(allocate response) A(free request) B(free response)
  • 30. An Execution History Time A(allocate request) B(allocate request) A(allocate response) B(allocate response)
  • 31. An Execution History Time A(allocate request) B(allocate request) A(allocate response) B(allocate response) “X happened before Y” => “Y may observe X to have occurred”
  • 32. A(allocate response) A(allocate request) B(allocate request) B(allocate response) Time
  • 33. A(allocate response) A(allocate request) B(allocate request) B(allocate response) Time
  • 34. A(allocate response) A(allocate request) B(allocate request) B(allocate response) A protocol violation! Time
  • 35. Time A(allocate response) A(allocate request) B(allocate request) B(allocate response)
  • 36. Time A(allocate response) A(allocate request) B(allocate request) B(allocate response)
  • 39. A Sequential History Time A(allocate request) A(allocate response) A(free request) A(free response) B(allocate request) B(allocate response)
  • 40. A Sequential History Time A(allocate request) A(allocate response) { } A(free request) A(free response) { } B(allocate request) B(allocate response) { }
  • 41. A Sequential History Time A(allocate request) A(allocate response) { } A(free request) A(free response) { } B(allocate request) B(allocate response) { }
  • 42. A Sequential History Time A(allocate request) A(allocate response) { } A(free request) A(free response) { } B(allocate request) B(allocate response) { }
  • 43. obj  *allocate(slab  *s)  {
 
    obj  *a  =  s-­‐>head;
    if  (a  ==  NULL)  return  NULL;
    s-­‐>head  =  a-­‐>next;
 
    return  a;
 }   void  free(slab  *s,  obj  *o)  {
    o-­‐>next  =  s-­‐>head;
    s-­‐>head  =  o;
 }
  • 44. obj  *allocate(slab  *s)  {
    lock(&allocator_lock);
    obj  *a  =  s-­‐>head;
    if  (a  ==  NULL)  return  NULL;
    s-­‐>head  =  a-­‐>next;
    unlock(&allocator_lock);
    return  a;
 }   void  free(slab  *s,  obj  *o)  {
    lock(&allocator_lock);      o-­‐>next  =  s-­‐>head;
    s-­‐>head  =  o;
    unlock(&allocator_lock);   }
  • 45. Was the State Locked? Yes Done No Atomic
  • 46. Fetch Old Lock State Set State Locked Was old State Locked? Yes Done No Atomic
  • 47. Fetch Old Lock State Set State Locked Was old State Locked? Yes Done No Atomic Test And Set Lock
  • 48. Test And Set Unlock Set State Unlocked Atomic
  • 49. typedef  spinlock  int;
 #define  LOCKED  1
 #define  UNLOCKED  0
 
 void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 }   void  unlock(spinlock  *m)  {
    atomic_store(m,  UNLOCKED);
 } Many code examples derived from Concurrency Kit http://concurrencykit.org
  • 50. void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } A(TAS request) A(TAS response) { }
  • 51. A(TAS request) A(TAS response) { } TAS is embedded in Lock
  • 52. A(TAS request) A(TAS response) { } A(lock request) A(lock response) Time TAS is embedded in Lock
  • 53. A(TAS request) A(TAS response) { } A(lock request) A(lock response) Time TAS & Store can’t be reordered
  • 54. A(TAS request) A(TAS response) { } A(lock request) A(lock response) Time B(unlock request) B(unlock response) B(Store request) B(Store response) { } TAS & Store can’t be reordered
  • 55.
  • 56. All execution histories All sequentially-consistent execution histories ⊇
  • 57. All execution histories All sequentially-consistent execution histories All ???able execution histories ⊇ ⊇
  • 58. All execution histories All sequentially-consistent execution histories All linearizable execution histories ⊇ ⊇
  • 59. A(TAS request) A(TAS response) { } A(lock request) A(lock response) Time Others can be reordered B(unlock request) B(unlock response) B(Store request) B(Store response) { }
  • 60. A(TAS request) A(TAS response) { } A(lock request) A(lock response) Time Others can be reordered B(unlock request) B(unlock response) B(Store request) B(Store response) { }
  • 61. void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 }   void  unlock(spinlock  *m)  {
    atomic_store(m,  UNLOCKED);
 }
  • 63. obj  *allocate(slab  *s)  {
    lock(&allocator_lock);
    obj  *a  =  s-­‐>head;
    if  (a  ==  NULL)  return  NULL;
    s-­‐>head  =  a-­‐>next;
    unlock(&allocator_lock);
    return  a;
 }   void  free(slab  *s,  obj  *o)  {
    lock(&allocator_lock);      o-­‐>next  =  s-­‐>head;
    s-­‐>head  =  o;
    unlock(&allocator_lock);   }
  • 64. void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 }   void  unlock(spinlock  *m)  {
    atomic_store(m,  UNLOCKED);
 }
  • 65. Spinlock performance millionsoflock acquisitions/sec 15 30 45 60 75 90 Threads 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 87.351 Test and Set
  • 66. Spinlock performance millionsoflock acquisitions/sec 15 30 45 60 75 90 Threads 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Platonic ideal of a spinlock
  • 67. Spinlock performance millionsoflock acquisitions/sec 15 30 45 60 75 90 Threads 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 87.351 4.343 Test and Set
  • 70. typedef  spinlock  int;
 #define  LOCKED  1
 #define  UNLOCKED  0
 
 void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 }  
  • 71. typedef  spinlock  int;
 #define  LOCKED  1
 #define  UNLOCKED  0
 
 void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)  {
        while  (atomic_store(m)  ==  LOCKED)              snooze();
    }
 }  
  • 72. typedef  spinlock  int;
 #define  LOCKED  1
 #define  UNLOCKED  0
 
 void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)  {
        while  (atomic_store(m)  ==  LOCKED)              snooze();
    }
 }   Test-and-Test-and-Set
  • 75. typedef  spinlock  int;
 #define  LOCKED  1
 #define  UNLOCKED  0
 
 void  lock(spinlock  *m)  {      unsigned  long  backoff,  exp  =  0;  
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)  {          for  (i  =  0;  i  <  backoff;  i++)              snooze();          backoff  =  (1ULL  <<  exp++);      }
 }  
  • 76. typedef  spinlock  int;
 #define  LOCKED  1
 #define  UNLOCKED  0
 
 void  lock(spinlock  *m)  {      unsigned  long  backoff,  exp  =  0;  
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)  {          for  (i  =  0;  i  <  backoff;  i++)              snooze();          backoff  =  (1ULL  <<  exp++);      }
 }   TAS + backoff
  • 78. void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } spinlock  global_lock  = UNLOCKED
  • 79. void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } spinlock  global_lock  = UNLOCKED
  • 80. void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } spinlock  global_lock  = UNLOCKED
  • 81. void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } spinlock  global_lock  = UNLOCKED
  • 82. void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } spinlock  global_lock  = LOCKED
  • 83. void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } spinlock  global_lock  = LOCKED
  • 84. void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } spinlock  global_lock  = LOCKED
  • 85. void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } spinlock  global_lock  = LOCKED
  • 86. void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } spinlock  global_lock  = LOCKED
  • 87. void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } void  lock(spinlock  *m)  {
    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
 } spinlock  global_lock  = LOCKED
  • 88. A function is lock-free if at all times at least one thread is guaranteed to be making progress [in the function]. (Herlihy & Shavit)
  • 89.
  • 90. //  TODO:  make  this  safe  and  scalable
 obj  *allocate(slab  *s)  {
    obj  *a  =  s-­‐>head;
    if  (a  ==  NULL)  return  NULL;
    s-­‐>head  =  a-­‐>next;
    return  a;
 }   //  TODO:  make  this  safe  and  scalable   void  free(slab  *s,  obj  *o)  {      o-­‐>next  =  s-­‐>head;
    s-­‐>head  =  o;   }
  • 93. Compare-And-Swap Cmpr and * Old value Destination Address
  • 95. Compare-And-Swap Old value New value ≠ Return false = Destination Address Copy to * Return true Cmpr and *
  • 96. Compare-And-Swap Old value New value ≠ Return false = Destination Address Return true Atomic Copy to *Cmpr and *
  • 97. Atomic i  =  i+1; void  atomic_inc(int  *ptr)  {
    int  i,  i_plus_one;
    do  {          i  =  *ptr;          i_plus_one  =  i  +  1;
    }  while  (!cas(i,  i_plus_one,  ptr));   
 }
  • 98. void  atomic_inc(int  *ptr)  {
    int  i,  i_plus_one;
    do  {          i  =  *ptr;          i_plus_one  =  i  +  1;
    }  while  (!cas(i,  i_plus_one,  ptr));   
 } Atomic i  =  i+1;
  • 99. void  atomic_inc(int  *ptr)  {
    int  i,  i_plus_one;
    do  {          i  =  *ptr;          i_plus_one  =  i  +  1;
    }  while  (!cas(i,  i_plus_one,  ptr));   
 } Atomic i  =  i+1;
  • 100. void  atomic_inc(int  *ptr)  {
    int  i,  i_plus_one;
    do  {          i  =  *ptr;          i_plus_one  =  i  +  1;
    }  while  (!cas(i,  i_plus_one,  ptr));   
 } Atomic i  =  i+1;
  • 101. void  atomic_inc_mod_32(int  *ptr)  {
    int  i,  new_i;
    do  {          i  =  *ptr;          new_i  =  i  +  1;          new_i  =  new_i  %  32;
    }  while  (!cas(i,  new_i,  ptr));
 } Atomic i  =  (i+1)  %  32;
  • 102. TAS using CAS void  tas_loop(spinlock  *m)  {
    do  {          ;
    }  while  (!cas(UNLOCKED,  LOCKED,  m));   }
  • 103. Read/Modify/Write void  atomic_inc_mod_32(int  *ptr)  {
    int  i,  new_i;
    do  {          i  =  *ptr;                                          /*  Read  */          new_i  =  fancy_function();      /*  Modify  */
    }  while  (!cas(i,  new_i,  ptr));  /*  Write  */                                                    
 }
  • 104. Read/Modify/Write void  atomic_inc_mod_32(int  *ptr)  {
    int  i,  new_i;
    do  {          i  =  *ptr;                                          /*  Read  */          new_i  =  fancy_function();      /*  Modify  */
    }  while  (!cas(i,  new_i,  ptr));  /*  Write  */                                                          /*  (or  retry)  */
 }
  • 105. obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head  ));
    return  a;
 } slab head A B …
  • 106. obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head  ));
    return  a;
 } slab head A B …
  • 107. obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head  ));
    return  a;
 } A B …slab head
  • 108. B … slab head A obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head  ));
    return  a;
 }
  • 109. obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(    ,    ,                  ));
    return    a;
 } slab head a a b Cmpr and * &s->head A B … b a
  • 110. slab head Cmpr and Z obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(    ,    ,                  ));
    return    a;
 } a a b &s->head b a
  • 111. slab head Z A B Cmpr and obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(    ,    ,                  ));
    return    a;
 } a a b &s->head b a
  • 112. slab head B … Cmpr and obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(    ,    ,                  ));
    return    a;
 } a a b &s->head b a
  • 113. void  free(slab  *s,  obj  *o)  {          do  {                  obj  *t  =  s-­‐>head;                  o-­‐>next  =  t;          }  while  (!cas(t,  o,  &s-­‐>head));   } B …slab head
  • 114. void  free(slab  *s,  obj  *o)  {          do  {                  obj  *t  =  s-­‐>head;                  o-­‐>next  =  t;          }  while  (!cas(t,  o,  &s-­‐>head));   } slab head A B …
  • 115. A B Cslab head
  • 116. A B Cslab head
  • 117. obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 } A B Cslab head
  • 118. obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 } A B Cslab head
  • 119. A B C obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 } slab head
  • 120. A B C obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 } slab head
  • 121. A B C some_object  =  allocate(&shared_slab); slab head obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 }
  • 122. A B C some_object  =  allocate(&shared_slab); slab head obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 }
  • 123. B C A slab head some_object  =  allocate(&shared_slab); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 }
  • 124. B C A slab head some_object  =  allocate(&shared_slab); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 }
  • 125. B C another_obj  =  allocate(&shared_slab); A slab head some_object  =  allocate(&shared_slab); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 }
  • 126. B C another_obj  =  allocate(&shared_slab); A slab head some_object  =  allocate(&shared_slab); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 }
  • 127. C A B slab head another_obj  =  allocate(&shared_slab); some_object  =  allocate(&shared_slab); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 }
  • 128. C A B slab head another_obj  =  allocate(&shared_slab); some_object  =  allocate(&shared_slab); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 }
  • 129. B C A slab head another_obj  =  allocate(&shared_slab); free(&shared_slab,  some_object); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 }
  • 130. B C A slab head another_obj  =  allocate(&shared_slab); free(&shared_slab,  some_object); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 }
  • 131. B A Cslab head another_obj  =  allocate(&shared_slab); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 } free(&shared_slab,  some_object);
  • 132. B A Cslab head another_obj  =  allocate(&shared_slab); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 } free(&shared_slab,  some_object);
  • 133. B A Cslab head another_obj  =  allocate(&shared_slab); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 } free(&shared_slab,  some_object);
  • 134. B A Cslab head another_obj  =  allocate(&shared_slab); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 } free(&shared_slab,  some_object);
  • 135. free(&shared_slab,  some_object); B B Cslab head A another_obj  =  allocate(&shared_slab); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 }
  • 136. free(&shared_slab,  some_object); B B Cslab head A another_obj  =  allocate(&shared_slab); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 }
  • 137. free(&shared_slab,  some_object); B B Cslab head A another_obj  =  allocate(&shared_slab); obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 }
  • 138. The ABA Problem “A reference about to be modified by a CAS changes from a to b and back to a again. As a result, the CAS succeeds even though its effect on the data structure has changed and no longer has the desired effect.” —Herlihy & Shavit, p. 235
  • 139. obj  *allocate(slab  *s)  {
    obj  *a,  *b;
    do  {
        a  =  s-­‐>head;
        if  (a  ==  NULL)  return  NULL;
        b  =  a-­‐>next;
    }  while  (!cas(a,  b,  &s-­‐>head));
    return  a;
 } A B …slab head 166
  • 140. obj  *allocate(slab  *s)  {
    slab  orig,  update;
    do  {
        orig.gen  =  s.gen;
        orig.head  =  s.head;
        if  (!orig.head)  return  NULL;          update.gen  =  orig.gen  +  1;
        update.head  =  orig.head-­‐>next;
    }  while  (!dcas(&orig,  &update,  s));
    return  orig.head;
 } A B …slab head 166
  • 141. free(slab  *s,  obj  *o)  {          do  {                  obj  *t  =  s-­‐>head;                  o-­‐>next  =  t;          }  while  (!cas(t,  o,  &s-­‐>head));   }
  • 142. obj  *allocate(slab  *s)  {
    lock(&allocator_lock);
    obj  *a  =  s-­‐>head;
    if  (a  ==  NULL)  return  NULL;
    s-­‐>head  =  a-­‐>next;
    unlock(&allocator_lock);
    return  a;
 }   void  free(slab  *s,  obj  *o)  {
    lock(&allocator_lock);      o-­‐>next  =  s-­‐>head;
    s-­‐>head  =  o;
    unlock(&allocator_lock);   }
  • 143. slab head A B … obj  *o  =  allocate(&shared_slab); obj  *o  =  allocate(&shared_slab);
  • 144. slab head B … obj  *o  =  allocate(&shared_slab); obj  *o  =  allocate(&shared_slab); A A
  • 145. slab head B … obj  *o  =  allocate(&shared_slab); obj  *o  =  allocate(&shared_slab); A A Memory barriers
  • 146.    lock(&allocator_lock);
    obj  *a  =  s-­‐>head;
 …    lock(&allocator_lock);
    obj  *a  =  s-­‐>head;
 …
  • 147.    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
    obj  *a  =  s-­‐>head;
 …    while  (atomic_tas(m,  LOCKED)  ==  LOCKED)          snooze();
    obj  *a  =  s-­‐>head;
 …
  • 148.    LDREX  R5,  [m]                      ;  TAS:  fetch.  .  .      STREXEQ  R5,  LOCKED,  [m]  ;  TAS:  .  .  .  and  set      CMPEQ  R5,  #0                        ;  Did  we  succeed?  LDR  R0,  [R1,  4]                  ;  a  =  s-­‐>head    BEQ  lock_done                      ;  Yes:  we  are  all  done
    BL  snooze                              ;  No:  Call  snooze()…
    B  lock_loop                          ;          …then  loop  again
 lock_done:      B  LR                                        ;  return ;;;;  IN  lock()   lock_loop:   ;;;;  IN  allocate()  
  • 149.    LDREX  R5,  [m]                      ;  TAS:  fetch.  .  .      STREXEQ  R5,  LOCKED,  [m]  ;  TAS:  .  .  .  and  set      CMPEQ  R5,  #0                        ;  Did  we  succeed?  LDR  R0,  [R1,  4]                  ;  a  =  s-­‐>head    BEQ  lock_done                      ;  Yes:  we  are  all  done
    BL  snooze                              ;  No:  Call  snooze()…
    B  lock_loop                          ;          …then  loop  again
 lock_done:      B  LR                                        ;  return ;;;;  IN  allocate()   ;;;;  IN  lock()   lock_loop:  
  • 150.  LDR  R0,  [R1,  4]                  ;  a  =  s-­‐>head    BEQ  lock_done                      ;  Yes:  we  are  all  done
    BL  snooze                              ;  No:  Call  snooze()…
    B  lock_loop                          ;          …then  loop  again
 lock_done:      B  LR                                        ;  return ;;;;  IN  allocate()      LDREX  R5,  [m]                      ;  TAS:  fetch.  .  .      STREXEQ  R5,  LOCKED,  [m]  ;  TAS:  .  .  .  and  set      CMPEQ  R5,  #0                        ;  Did  we  succeed? ;;;;  IN  lock()   lock_loop:  
  • 155.
  • 156.    LDREX  R5,  [m]                      ;  TAS:  fetch.  .  .      STREXEQ  R5,  LOCKED,  [m]  ;  TAS:  .  .  .  and  set      CMPEQ  R5,  #0                        ;  Did  we  succeed?  LDR  R0,  [R1,  4]                  ;  a  =  s-­‐>head    BEQ  lock_done                      ;  Yes:  we  are  all  done
    BL  snooze                              ;  No:  Call  snooze()…
    B  lock_loop                          ;          …then  loop  again
 lock_done:      B  LR                                        ;  return ;;;;  IN  allocate()   ;;;;  IN  lock()   lock_loop:  
  • 157.    LDREX  R5,  [m]                      ;  TAS:  fetch.  .  .      STREXEQ  R5,  LOCKED,  [m]  ;  TAS:  .  .  .  and  set      CMPEQ  R5,  #0                        ;  Did  we  succeed?  LDR  R0,  [R1,  4]                  ;  a  =  s-­‐>head    BEQ  lock_done                      ;  Yes:  we  are  all  done
    BL  snooze                              ;  No:  Call  snooze()…
    B  lock_loop                          ;          …then  loop  again
 lock_done:      B  LR                                        ;  return ;;;;  IN  allocate()   ;;;;  IN  lock()   lock_loop:  
  • 158.
  • 159.    obj  *a  =  s-­‐>head;      lock(&allocator_lock);
 …    obj  *a  =  s-­‐>head;
    lock(&allocator_lock);
 …
  • 160.    lock(&allocator_lock);
    obj  *a  =  s-­‐>head;
 …    lock(&allocator_lock);
    obj  *a  =  s-­‐>head;
 …
  • 161.    lock(&allocator_lock);      <  -­‐  -­‐  -­‐  -­‐  -­‐  -­‐  -­‐  -­‐  -­‐  -­‐>
    obj  *a  =  s-­‐>head;
 …    lock(&allocator_lock);      <  -­‐  -­‐  -­‐  -­‐  -­‐  -­‐  -­‐  -­‐  -­‐  -­‐>
    obj  *a  =  s-­‐>head;
 …
  • 162.
  • 163.    LDREX  R5,  [m]                      ;  TAS:  fetch.  .  .      STREXEQ  R5,  LOCKED,  [m]  ;  TAS:  .  .  .  and  set      CMPEQ  R5,  #0                        ;  Did  we  succeed?    BEQ  lock_done                      ;  Yes:  we  are  all  done
    BL  snooze                              ;  No:  Call  snooze()…
    B  lock_loop                          ;          …then  loop  again
 lock_done:      DMB                                          ;  Ensure  all  previous  reads                                                      ;  have  been  completed      B  LR                                        ;  return ;;;;  IN  unlock()      MOV  R0,  UNLOCKED      DMB                            ;  Ensure  all  previous  reads  have                                        ;  been  completed      STR  R0,  LR ;;;;  IN  lock()   lock_loop:  
  • 164. nathan~$  cat  /proc/cpuinfo  |  grep  "physical.*0"  |  wc  -­‐l   16   nathan~$  cat  /proc/cpuinfo  |  grep  "model  name"  |  uniq   model  name  :  Intel(R)  Xeon(R)  CPU  E5-­‐2690  0  @  2.90GHz Allocator performance
  • 166. MillionsofAlloc/free
 pairs/sec 10 20 30 40 50 60 Threads 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 TAS T&T&S TAS + EB Concurrent Allocator pthread Allocator Throughput
  • 173. The lyf so short, the CAS so longe to lerne • Cache coherency and NUMA architecture • Transactional memory
  • 175. a safe race? When is a race
  • 176.
  • 177. “lock-free programming is hard; let’s go ride bikes”?
  • 178. “lock-free programming is hard; let’s go ride bikes”? • high-level performance necessitates an understanding of low level performance
  • 179. “lock-free programming is hard; let’s go ride bikes”? • high-level performance necessitates an understanding of low level performance • your computer is a distributed system
  • 180. “lock-free programming is hard; let’s go ride bikes”? • high-level performance necessitates an understanding of low level performance • your computer is a distributed system • (optional third answer: it’s real neato)
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187. Come see us at the booth! Nathan Taylor | nathan.dijkstracula.net | @dijkstracula Thanks credits, code, and additional material at https://github.com/dijkstracula/Surge2015/