SlideShare una empresa de Scribd logo
1 de 187
Descargar para leer sin conexión
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/

Más contenido relacionado

La actualidad más candente

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
 

La actualidad más candente (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
 

Similar a 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
 

Similar a 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
 

Más de 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
 

Más de 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
 

Último

20240507 QFM013 Machine Intelligence Reading List April 2024.pdf
20240507 QFM013 Machine Intelligence Reading List April 2024.pdf20240507 QFM013 Machine Intelligence Reading List April 2024.pdf
20240507 QFM013 Machine Intelligence Reading List April 2024.pdfMatthew Sinclair
 
Microsoft Azure Arc Customer Deck Microsoft
Microsoft Azure Arc Customer Deck MicrosoftMicrosoft Azure Arc Customer Deck Microsoft
Microsoft Azure Arc Customer Deck MicrosoftAanSulistiyo
 
Power point inglese - educazione civica di Nuria Iuzzolino
Power point inglese - educazione civica di Nuria IuzzolinoPower point inglese - educazione civica di Nuria Iuzzolino
Power point inglese - educazione civica di Nuria Iuzzolinonuriaiuzzolino1
 
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...gajnagarg
 
Vip Firozabad Phone 8250092165 Escorts Service At 6k To 30k Along With Ac Room
Vip Firozabad Phone 8250092165 Escorts Service At 6k To 30k Along With Ac RoomVip Firozabad Phone 8250092165 Escorts Service At 6k To 30k Along With Ac Room
Vip Firozabad Phone 8250092165 Escorts Service At 6k To 30k Along With Ac Roommeghakumariji156
 
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdfpdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdfJOHNBEBONYAP1
 
Best SEO Services Company in Dallas | Best SEO Agency Dallas
Best SEO Services Company in Dallas | Best SEO Agency DallasBest SEO Services Company in Dallas | Best SEO Agency Dallas
Best SEO Services Company in Dallas | Best SEO Agency DallasDigicorns Technologies
 
APNIC Updates presented by Paul Wilson at ARIN 53
APNIC Updates presented by Paul Wilson at ARIN 53APNIC Updates presented by Paul Wilson at ARIN 53
APNIC Updates presented by Paul Wilson at ARIN 53APNIC
 
在线制作约克大学毕业证(yu毕业证)在读证明认证可查
在线制作约克大学毕业证(yu毕业证)在读证明认证可查在线制作约克大学毕业证(yu毕业证)在读证明认证可查
在线制作约克大学毕业证(yu毕业证)在读证明认证可查ydyuyu
 
哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查
哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查
哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查ydyuyu
 
best call girls in Hyderabad Finest Escorts Service 📞 9352988975 📞 Available ...
best call girls in Hyderabad Finest Escorts Service 📞 9352988975 📞 Available ...best call girls in Hyderabad Finest Escorts Service 📞 9352988975 📞 Available ...
best call girls in Hyderabad Finest Escorts Service 📞 9352988975 📞 Available ...kajalverma014
 
2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs
2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs
2nd Solid Symposium: Solid Pods vs Personal Knowledge GraphsEleniIlkou
 
"Boost Your Digital Presence: Partner with a Leading SEO Agency"
"Boost Your Digital Presence: Partner with a Leading SEO Agency""Boost Your Digital Presence: Partner with a Leading SEO Agency"
"Boost Your Digital Presence: Partner with a Leading SEO Agency"growthgrids
 
75539-Cyber Security Challenges PPT.pptx
75539-Cyber Security Challenges PPT.pptx75539-Cyber Security Challenges PPT.pptx
75539-Cyber Security Challenges PPT.pptxAsmae Rabhi
 
Story Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
Story Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrStory Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
Story Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrHenryBriggs2
 
Nagercoil Escorts Service Girl ^ 9332606886, WhatsApp Anytime Nagercoil
Nagercoil Escorts Service Girl ^ 9332606886, WhatsApp Anytime NagercoilNagercoil Escorts Service Girl ^ 9332606886, WhatsApp Anytime Nagercoil
Nagercoil Escorts Service Girl ^ 9332606886, WhatsApp Anytime Nagercoilmeghakumariji156
 
Trump Diapers Over Dems t shirts Sweatshirt
Trump Diapers Over Dems t shirts SweatshirtTrump Diapers Over Dems t shirts Sweatshirt
Trump Diapers Over Dems t shirts Sweatshirtrahman018755
 
APNIC Policy Roundup, presented by Sunny Chendi at the 5th ICANN APAC-TWNIC E...
APNIC Policy Roundup, presented by Sunny Chendi at the 5th ICANN APAC-TWNIC E...APNIC Policy Roundup, presented by Sunny Chendi at the 5th ICANN APAC-TWNIC E...
APNIC Policy Roundup, presented by Sunny Chendi at the 5th ICANN APAC-TWNIC E...APNIC
 
Russian Escort Abu Dhabi 0503464457 Abu DHabi Escorts
Russian Escort Abu Dhabi 0503464457 Abu DHabi EscortsRussian Escort Abu Dhabi 0503464457 Abu DHabi Escorts
Russian Escort Abu Dhabi 0503464457 Abu DHabi EscortsMonica Sydney
 
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
20240509 QFM015 Engineering Leadership Reading List April 2024.pdfMatthew Sinclair
 

Último (20)

20240507 QFM013 Machine Intelligence Reading List April 2024.pdf
20240507 QFM013 Machine Intelligence Reading List April 2024.pdf20240507 QFM013 Machine Intelligence Reading List April 2024.pdf
20240507 QFM013 Machine Intelligence Reading List April 2024.pdf
 
Microsoft Azure Arc Customer Deck Microsoft
Microsoft Azure Arc Customer Deck MicrosoftMicrosoft Azure Arc Customer Deck Microsoft
Microsoft Azure Arc Customer Deck Microsoft
 
Power point inglese - educazione civica di Nuria Iuzzolino
Power point inglese - educazione civica di Nuria IuzzolinoPower point inglese - educazione civica di Nuria Iuzzolino
Power point inglese - educazione civica di Nuria Iuzzolino
 
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
 
Vip Firozabad Phone 8250092165 Escorts Service At 6k To 30k Along With Ac Room
Vip Firozabad Phone 8250092165 Escorts Service At 6k To 30k Along With Ac RoomVip Firozabad Phone 8250092165 Escorts Service At 6k To 30k Along With Ac Room
Vip Firozabad Phone 8250092165 Escorts Service At 6k To 30k Along With Ac Room
 
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdfpdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
 
Best SEO Services Company in Dallas | Best SEO Agency Dallas
Best SEO Services Company in Dallas | Best SEO Agency DallasBest SEO Services Company in Dallas | Best SEO Agency Dallas
Best SEO Services Company in Dallas | Best SEO Agency Dallas
 
APNIC Updates presented by Paul Wilson at ARIN 53
APNIC Updates presented by Paul Wilson at ARIN 53APNIC Updates presented by Paul Wilson at ARIN 53
APNIC Updates presented by Paul Wilson at ARIN 53
 
在线制作约克大学毕业证(yu毕业证)在读证明认证可查
在线制作约克大学毕业证(yu毕业证)在读证明认证可查在线制作约克大学毕业证(yu毕业证)在读证明认证可查
在线制作约克大学毕业证(yu毕业证)在读证明认证可查
 
哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查
哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查
哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查
 
best call girls in Hyderabad Finest Escorts Service 📞 9352988975 📞 Available ...
best call girls in Hyderabad Finest Escorts Service 📞 9352988975 📞 Available ...best call girls in Hyderabad Finest Escorts Service 📞 9352988975 📞 Available ...
best call girls in Hyderabad Finest Escorts Service 📞 9352988975 📞 Available ...
 
2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs
2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs
2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs
 
"Boost Your Digital Presence: Partner with a Leading SEO Agency"
"Boost Your Digital Presence: Partner with a Leading SEO Agency""Boost Your Digital Presence: Partner with a Leading SEO Agency"
"Boost Your Digital Presence: Partner with a Leading SEO Agency"
 
75539-Cyber Security Challenges PPT.pptx
75539-Cyber Security Challenges PPT.pptx75539-Cyber Security Challenges PPT.pptx
75539-Cyber Security Challenges PPT.pptx
 
Story Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
Story Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrStory Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
Story Board.pptxrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
 
Nagercoil Escorts Service Girl ^ 9332606886, WhatsApp Anytime Nagercoil
Nagercoil Escorts Service Girl ^ 9332606886, WhatsApp Anytime NagercoilNagercoil Escorts Service Girl ^ 9332606886, WhatsApp Anytime Nagercoil
Nagercoil Escorts Service Girl ^ 9332606886, WhatsApp Anytime Nagercoil
 
Trump Diapers Over Dems t shirts Sweatshirt
Trump Diapers Over Dems t shirts SweatshirtTrump Diapers Over Dems t shirts Sweatshirt
Trump Diapers Over Dems t shirts Sweatshirt
 
APNIC Policy Roundup, presented by Sunny Chendi at the 5th ICANN APAC-TWNIC E...
APNIC Policy Roundup, presented by Sunny Chendi at the 5th ICANN APAC-TWNIC E...APNIC Policy Roundup, presented by Sunny Chendi at the 5th ICANN APAC-TWNIC E...
APNIC Policy Roundup, presented by Sunny Chendi at the 5th ICANN APAC-TWNIC E...
 
Russian Escort Abu Dhabi 0503464457 Abu DHabi Escorts
Russian Escort Abu Dhabi 0503464457 Abu DHabi EscortsRussian Escort Abu Dhabi 0503464457 Abu DHabi Escorts
Russian Escort Abu Dhabi 0503464457 Abu DHabi Escorts
 
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
 

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/