Merge pull request #4902 from nicolasnoble/win32-cleanup

Cleaning up Windows compilation.
diff --git a/Makefile b/Makefile
index 8dfb505..2270fc3 100644
--- a/Makefile
+++ b/Makefile
@@ -208,7 +208,7 @@
 CXXFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie
 LDFLAGS_msan = -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
 DEFINES_msan = NDEBUG
-DEFINES_msan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=1.5
+DEFINES_msan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=2
 
 VALID_CONFIG_mutrace = 1
 CC_mutrace = $(DEFAULT_CC)
@@ -226,26 +226,44 @@
 
 prefix ?= /usr/local
 
-PROTOC = protoc
-DTRACE = dtrace
+PROTOC ?= protoc
+DTRACE ?= dtrace
 CONFIG ?= opt
+# Doing X ?= Y is the same as:
+# ifeq ($(origin X), undefined)
+#  X = Y
+# endif
+# but some variables, such as CC, CXX, LD or AR, have defaults.
+# So instead of using ?= on them, we need to check their origin.
+# See:
+#  https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html
+#  https://www.gnu.org/software/make/manual/html_node/Flavors.html#index-_003f_003d
+#  https://www.gnu.org/software/make/manual/html_node/Origin-Function.html
+ifeq ($(origin CC), default)
 CC = $(CC_$(CONFIG))
+endif
+ifeq ($(origin CXX), default)
 CXX = $(CXX_$(CONFIG))
+endif
+ifeq ($(origin LD), default)
 LD = $(LD_$(CONFIG))
-LDXX = $(LDXX_$(CONFIG))
+endif
+LDXX ?= $(LDXX_$(CONFIG))
+ifeq ($(origin AR), default)
 AR = ar
+endif
 ifeq ($(SYSTEM),Linux)
-STRIP = strip --strip-unneeded
+STRIP ?= strip --strip-unneeded
 else
 ifeq ($(SYSTEM),Darwin)
-STRIP = strip -x
+STRIP ?= strip -x
 else
-STRIP = strip
+STRIP ?= strip
 endif
 endif
-INSTALL = install
-RM = rm -f
-PKG_CONFIG = pkg-config
+INSTALL ?= install
+RM ?= rm -f
+PKG_CONFIG ?= pkg-config
 
 ifndef VALID_CONFIG_$(CONFIG)
 $(error Invalid CONFIG value '$(CONFIG)')
@@ -261,15 +279,21 @@
 CXX11_CHECK_CMD = $(CXX) -std=c++11 -o $(TMPOUT) -c test/build/c++11.cc
 HAS_CXX11 = $(shell $(CXX11_CHECK_CMD) 2> /dev/null && echo true || echo false)
 
+CHECK_NO_SHIFT_NEGATIVE_VALUE_CMD = $(CC) -std=c99 -Werror -Wno-shift-negative-value -o $(TMPOUT) -c test/build/empty.c
+HAS_NO_SHIFT_NEGATIVE_VALUE = $(shell $(CHECK_NO_SHIFT_NEGATIVE_VALUE_CMD) 2> /dev/null && echo true || echo false)
+ifeq ($(HAS_NO_SHIFT_NEGATIVE_VALUE),true)
+W_NO_SHIFT_NEGATIVE_VALUE=-Wno-shift-negative-value
+endif
+
 # The HOST compiler settings are used to compile the protoc plugins.
 # In most cases, you won't have to change anything, but if you are
 # cross-compiling, you can override these variables from GNU make's
 # command line: make CC=cross-gcc HOST_CC=gcc
 
-HOST_CC = $(CC)
-HOST_CXX = $(CXX)
-HOST_LD = $(LD)
-HOST_LDXX = $(LDXX)
+HOST_CC ?= $(CC)
+HOST_CXX ?= $(CXX)
+HOST_LD ?= $(LD)
+HOST_LDXX ?= $(LDXX)
 
 ifdef EXTRA_DEFINES
 DEFINES += $(EXTRA_DEFINES)
@@ -400,14 +424,6 @@
 IS_GIT_FOLDER = true
 endif
 
-ifeq ($(SYSTEM),Linux)
-OPENSSL_REQUIRES_DL = true
-endif
-
-ifeq ($(SYSTEM),Darwin)
-OPENSSL_REQUIRES_DL = true
-endif
-
 ifeq ($(HAS_PKG_CONFIG),true)
 OPENSSL_ALPN_CHECK_CMD = $(PKG_CONFIG) --atleast-version=1.0.2 openssl
 OPENSSL_NPN_CHECK_CMD = $(PKG_CONFIG) --atleast-version=1.0.1 openssl
@@ -426,11 +442,6 @@
 ZLIB_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/zlib.c -lz $(LDFLAGS)
 PROTOBUF_CHECK_CMD = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/protobuf.cc -lprotobuf $(LDFLAGS)
 
-ifeq ($(OPENSSL_REQUIRES_DL),true)
-OPENSSL_ALPN_CHECK_CMD += -ldl
-OPENSSL_NPN_CHECK_CMD += -ldl
-endif
-
 endif # HAS_PKG_CONFIG
 
 PERFTOOLS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/perftools.c -lprofiler $(LDFLAGS)
@@ -594,9 +605,6 @@
 OPENSSL_MERGE_LIBS += $(LIBDIR)/$(CONFIG)/libboringssl.a
 # need to prefix these to ensure overriding system libraries
 CPPFLAGS := -Ithird_party/boringssl/include $(CPPFLAGS)
-ifeq ($(OPENSSL_REQUIRES_DL),true)
-LIBS_SECURE = dl
-endif # OPENSSL_REQUIRES_DL
 else # EMBED_OPENSSL=false
 ifeq ($(HAS_PKG_CONFIG),true)
 OPENSSL_PKG_CONFIG = true
@@ -616,10 +624,7 @@
 CPPFLAGS += -DTSI_OPENSSL_ALPN_SUPPORT=0
 LIBS_SECURE = $(OPENSSL_LIBS)
 endif # HAS_SYSTEM_OPENSSL_NPN
-ifeq ($(OPENSSL_REQUIRES_DL),true)
-LIBS_SECURE += dl
 PC_LIBS_SECURE = $(addprefix -l, $(LIBS_SECURE))
-endif # OPENSSL_REQUIRES_DL=true
 endif # EMBED_OPENSSL
 endif # NO_SECURE
 
@@ -5486,7 +5491,7 @@
 
 LIBZ_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBZ_SRC))))
 
-$(LIBZ_OBJS): CFLAGS := $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration -fvisibility=hidden
+$(LIBZ_OBJS): CFLAGS := $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration $(W_NO_SHIFT_NEGATIVE_VALUE) -fvisibility=hidden
 
 $(LIBDIR)/$(CONFIG)/libz.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBZ_OBJS)
 	$(E) "[AR]      Creating $@"
diff --git a/binding.gyp b/binding.gyp
index f6d60b9..b1c0214 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -5,7 +5,7 @@
 # This file can be regenerated from the template by running
 # tools/buildgen/generate_projects.sh
 
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -54,12 +54,16 @@
     ],
     'include_dirs': [
       '.',
-      'include',
-      '<(node_root_dir)/deps/openssl/openssl/include',
-      '<(node_root_dir)/deps/zlib'
+      'include'
     ],
     'conditions': [
-      ['OS != "win"', {
+      ['OS == "win"', {
+        "include_dirs": [ "third_party/boringssl/include" ]
+      }, {
+        'include_dirs': [
+          '<(node_root_dir)/deps/openssl/openssl/include',
+          '<(node_root_dir)/deps/zlib'
+        ],
         'conditions': [
           ['config=="gcov"', {
             'cflags': [
@@ -72,20 +76,366 @@
               '-fprofile-arcs'
             ]
           }
-         ]
+         ],
+         ["target_arch=='ia32'", {
+             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/piii" ]
+         }],
+         ["target_arch=='x64'", {
+             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/k8" ]
+         }],
+         ["target_arch=='arm'", {
+             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/arm" ]
+         }]
         ]
-      }],
-      ["target_arch=='ia32'", {
-          "include_dirs": [ "<(node_root_dir)/deps/openssl/config/piii" ]
-      }],
-      ["target_arch=='x64'", {
-          "include_dirs": [ "<(node_root_dir)/deps/openssl/config/k8" ]
-      }],
-      ["target_arch=='arm'", {
-          "include_dirs": [ "<(node_root_dir)/deps/openssl/config/arm" ]
       }]
     ]
   },
+  'conditions': [
+    ['OS == "win"', {
+      'targets': [
+        # Only want to compile BoringSSL and zlib under Windows
+        {
+          'cflags': [
+            '-std=c99',
+            '-Wall',
+            '-Werror'
+          ],
+          'target_name': 'boringssl',
+          'product_prefix': 'lib',
+          'type': 'static_library',
+          'dependencies': [
+          ],
+          'sources': [
+            'src/boringssl/err_data.c',
+            'third_party/boringssl/crypto/aes/aes.c',
+            'third_party/boringssl/crypto/aes/mode_wrappers.c',
+            'third_party/boringssl/crypto/asn1/a_bitstr.c',
+            'third_party/boringssl/crypto/asn1/a_bool.c',
+            'third_party/boringssl/crypto/asn1/a_bytes.c',
+            'third_party/boringssl/crypto/asn1/a_d2i_fp.c',
+            'third_party/boringssl/crypto/asn1/a_dup.c',
+            'third_party/boringssl/crypto/asn1/a_enum.c',
+            'third_party/boringssl/crypto/asn1/a_gentm.c',
+            'third_party/boringssl/crypto/asn1/a_i2d_fp.c',
+            'third_party/boringssl/crypto/asn1/a_int.c',
+            'third_party/boringssl/crypto/asn1/a_mbstr.c',
+            'third_party/boringssl/crypto/asn1/a_object.c',
+            'third_party/boringssl/crypto/asn1/a_octet.c',
+            'third_party/boringssl/crypto/asn1/a_print.c',
+            'third_party/boringssl/crypto/asn1/a_strnid.c',
+            'third_party/boringssl/crypto/asn1/a_time.c',
+            'third_party/boringssl/crypto/asn1/a_type.c',
+            'third_party/boringssl/crypto/asn1/a_utctm.c',
+            'third_party/boringssl/crypto/asn1/a_utf8.c',
+            'third_party/boringssl/crypto/asn1/asn1_lib.c',
+            'third_party/boringssl/crypto/asn1/asn1_par.c',
+            'third_party/boringssl/crypto/asn1/asn_pack.c',
+            'third_party/boringssl/crypto/asn1/bio_asn1.c',
+            'third_party/boringssl/crypto/asn1/bio_ndef.c',
+            'third_party/boringssl/crypto/asn1/f_enum.c',
+            'third_party/boringssl/crypto/asn1/f_int.c',
+            'third_party/boringssl/crypto/asn1/f_string.c',
+            'third_party/boringssl/crypto/asn1/t_bitst.c',
+            'third_party/boringssl/crypto/asn1/t_pkey.c',
+            'third_party/boringssl/crypto/asn1/tasn_dec.c',
+            'third_party/boringssl/crypto/asn1/tasn_enc.c',
+            'third_party/boringssl/crypto/asn1/tasn_fre.c',
+            'third_party/boringssl/crypto/asn1/tasn_new.c',
+            'third_party/boringssl/crypto/asn1/tasn_prn.c',
+            'third_party/boringssl/crypto/asn1/tasn_typ.c',
+            'third_party/boringssl/crypto/asn1/tasn_utl.c',
+            'third_party/boringssl/crypto/asn1/x_bignum.c',
+            'third_party/boringssl/crypto/asn1/x_long.c',
+            'third_party/boringssl/crypto/base64/base64.c',
+            'third_party/boringssl/crypto/bio/bio.c',
+            'third_party/boringssl/crypto/bio/bio_mem.c',
+            'third_party/boringssl/crypto/bio/buffer.c',
+            'third_party/boringssl/crypto/bio/connect.c',
+            'third_party/boringssl/crypto/bio/fd.c',
+            'third_party/boringssl/crypto/bio/file.c',
+            'third_party/boringssl/crypto/bio/hexdump.c',
+            'third_party/boringssl/crypto/bio/pair.c',
+            'third_party/boringssl/crypto/bio/printf.c',
+            'third_party/boringssl/crypto/bio/socket.c',
+            'third_party/boringssl/crypto/bio/socket_helper.c',
+            'third_party/boringssl/crypto/bn/add.c',
+            'third_party/boringssl/crypto/bn/asm/x86_64-gcc.c',
+            'third_party/boringssl/crypto/bn/bn.c',
+            'third_party/boringssl/crypto/bn/bn_asn1.c',
+            'third_party/boringssl/crypto/bn/cmp.c',
+            'third_party/boringssl/crypto/bn/convert.c',
+            'third_party/boringssl/crypto/bn/ctx.c',
+            'third_party/boringssl/crypto/bn/div.c',
+            'third_party/boringssl/crypto/bn/exponentiation.c',
+            'third_party/boringssl/crypto/bn/gcd.c',
+            'third_party/boringssl/crypto/bn/generic.c',
+            'third_party/boringssl/crypto/bn/kronecker.c',
+            'third_party/boringssl/crypto/bn/montgomery.c',
+            'third_party/boringssl/crypto/bn/mul.c',
+            'third_party/boringssl/crypto/bn/prime.c',
+            'third_party/boringssl/crypto/bn/random.c',
+            'third_party/boringssl/crypto/bn/rsaz_exp.c',
+            'third_party/boringssl/crypto/bn/shift.c',
+            'third_party/boringssl/crypto/bn/sqrt.c',
+            'third_party/boringssl/crypto/buf/buf.c',
+            'third_party/boringssl/crypto/bytestring/ber.c',
+            'third_party/boringssl/crypto/bytestring/cbb.c',
+            'third_party/boringssl/crypto/bytestring/cbs.c',
+            'third_party/boringssl/crypto/chacha/chacha_generic.c',
+            'third_party/boringssl/crypto/chacha/chacha_vec.c',
+            'third_party/boringssl/crypto/cipher/aead.c',
+            'third_party/boringssl/crypto/cipher/cipher.c',
+            'third_party/boringssl/crypto/cipher/derive_key.c',
+            'third_party/boringssl/crypto/cipher/e_aes.c',
+            'third_party/boringssl/crypto/cipher/e_chacha20poly1305.c',
+            'third_party/boringssl/crypto/cipher/e_des.c',
+            'third_party/boringssl/crypto/cipher/e_null.c',
+            'third_party/boringssl/crypto/cipher/e_rc2.c',
+            'third_party/boringssl/crypto/cipher/e_rc4.c',
+            'third_party/boringssl/crypto/cipher/e_ssl3.c',
+            'third_party/boringssl/crypto/cipher/e_tls.c',
+            'third_party/boringssl/crypto/cipher/tls_cbc.c',
+            'third_party/boringssl/crypto/cmac/cmac.c',
+            'third_party/boringssl/crypto/conf/conf.c',
+            'third_party/boringssl/crypto/cpu-arm.c',
+            'third_party/boringssl/crypto/cpu-intel.c',
+            'third_party/boringssl/crypto/crypto.c',
+            'third_party/boringssl/crypto/curve25519/curve25519.c',
+            'third_party/boringssl/crypto/des/des.c',
+            'third_party/boringssl/crypto/dh/check.c',
+            'third_party/boringssl/crypto/dh/dh.c',
+            'third_party/boringssl/crypto/dh/dh_asn1.c',
+            'third_party/boringssl/crypto/dh/params.c',
+            'third_party/boringssl/crypto/digest/digest.c',
+            'third_party/boringssl/crypto/digest/digests.c',
+            'third_party/boringssl/crypto/directory_posix.c',
+            'third_party/boringssl/crypto/directory_win.c',
+            'third_party/boringssl/crypto/dsa/dsa.c',
+            'third_party/boringssl/crypto/dsa/dsa_asn1.c',
+            'third_party/boringssl/crypto/ec/ec.c',
+            'third_party/boringssl/crypto/ec/ec_asn1.c',
+            'third_party/boringssl/crypto/ec/ec_key.c',
+            'third_party/boringssl/crypto/ec/ec_montgomery.c',
+            'third_party/boringssl/crypto/ec/oct.c',
+            'third_party/boringssl/crypto/ec/p224-64.c',
+            'third_party/boringssl/crypto/ec/p256-64.c',
+            'third_party/boringssl/crypto/ec/p256-x86_64.c',
+            'third_party/boringssl/crypto/ec/simple.c',
+            'third_party/boringssl/crypto/ec/util-64.c',
+            'third_party/boringssl/crypto/ec/wnaf.c',
+            'third_party/boringssl/crypto/ecdh/ecdh.c',
+            'third_party/boringssl/crypto/ecdsa/ecdsa.c',
+            'third_party/boringssl/crypto/ecdsa/ecdsa_asn1.c',
+            'third_party/boringssl/crypto/engine/engine.c',
+            'third_party/boringssl/crypto/err/err.c',
+            'third_party/boringssl/crypto/evp/algorithm.c',
+            'third_party/boringssl/crypto/evp/digestsign.c',
+            'third_party/boringssl/crypto/evp/evp.c',
+            'third_party/boringssl/crypto/evp/evp_asn1.c',
+            'third_party/boringssl/crypto/evp/evp_ctx.c',
+            'third_party/boringssl/crypto/evp/p_dsa_asn1.c',
+            'third_party/boringssl/crypto/evp/p_ec.c',
+            'third_party/boringssl/crypto/evp/p_ec_asn1.c',
+            'third_party/boringssl/crypto/evp/p_rsa.c',
+            'third_party/boringssl/crypto/evp/p_rsa_asn1.c',
+            'third_party/boringssl/crypto/evp/pbkdf.c',
+            'third_party/boringssl/crypto/evp/sign.c',
+            'third_party/boringssl/crypto/ex_data.c',
+            'third_party/boringssl/crypto/hkdf/hkdf.c',
+            'third_party/boringssl/crypto/hmac/hmac.c',
+            'third_party/boringssl/crypto/lhash/lhash.c',
+            'third_party/boringssl/crypto/md4/md4.c',
+            'third_party/boringssl/crypto/md5/md5.c',
+            'third_party/boringssl/crypto/mem.c',
+            'third_party/boringssl/crypto/modes/cbc.c',
+            'third_party/boringssl/crypto/modes/cfb.c',
+            'third_party/boringssl/crypto/modes/ctr.c',
+            'third_party/boringssl/crypto/modes/gcm.c',
+            'third_party/boringssl/crypto/modes/ofb.c',
+            'third_party/boringssl/crypto/obj/obj.c',
+            'third_party/boringssl/crypto/obj/obj_xref.c',
+            'third_party/boringssl/crypto/pem/pem_all.c',
+            'third_party/boringssl/crypto/pem/pem_info.c',
+            'third_party/boringssl/crypto/pem/pem_lib.c',
+            'third_party/boringssl/crypto/pem/pem_oth.c',
+            'third_party/boringssl/crypto/pem/pem_pk8.c',
+            'third_party/boringssl/crypto/pem/pem_pkey.c',
+            'third_party/boringssl/crypto/pem/pem_x509.c',
+            'third_party/boringssl/crypto/pem/pem_xaux.c',
+            'third_party/boringssl/crypto/pkcs8/p5_pbe.c',
+            'third_party/boringssl/crypto/pkcs8/p5_pbev2.c',
+            'third_party/boringssl/crypto/pkcs8/p8_pkey.c',
+            'third_party/boringssl/crypto/pkcs8/pkcs8.c',
+            'third_party/boringssl/crypto/poly1305/poly1305.c',
+            'third_party/boringssl/crypto/poly1305/poly1305_arm.c',
+            'third_party/boringssl/crypto/poly1305/poly1305_vec.c',
+            'third_party/boringssl/crypto/rand/rand.c',
+            'third_party/boringssl/crypto/rand/urandom.c',
+            'third_party/boringssl/crypto/rand/windows.c',
+            'third_party/boringssl/crypto/rc4/rc4.c',
+            'third_party/boringssl/crypto/refcount_c11.c',
+            'third_party/boringssl/crypto/refcount_lock.c',
+            'third_party/boringssl/crypto/rsa/blinding.c',
+            'third_party/boringssl/crypto/rsa/padding.c',
+            'third_party/boringssl/crypto/rsa/rsa.c',
+            'third_party/boringssl/crypto/rsa/rsa_asn1.c',
+            'third_party/boringssl/crypto/rsa/rsa_impl.c',
+            'third_party/boringssl/crypto/sha/sha1.c',
+            'third_party/boringssl/crypto/sha/sha256.c',
+            'third_party/boringssl/crypto/sha/sha512.c',
+            'third_party/boringssl/crypto/stack/stack.c',
+            'third_party/boringssl/crypto/thread.c',
+            'third_party/boringssl/crypto/thread_none.c',
+            'third_party/boringssl/crypto/thread_pthread.c',
+            'third_party/boringssl/crypto/thread_win.c',
+            'third_party/boringssl/crypto/time_support.c',
+            'third_party/boringssl/crypto/x509/a_digest.c',
+            'third_party/boringssl/crypto/x509/a_sign.c',
+            'third_party/boringssl/crypto/x509/a_strex.c',
+            'third_party/boringssl/crypto/x509/a_verify.c',
+            'third_party/boringssl/crypto/x509/asn1_gen.c',
+            'third_party/boringssl/crypto/x509/by_dir.c',
+            'third_party/boringssl/crypto/x509/by_file.c',
+            'third_party/boringssl/crypto/x509/i2d_pr.c',
+            'third_party/boringssl/crypto/x509/pkcs7.c',
+            'third_party/boringssl/crypto/x509/t_crl.c',
+            'third_party/boringssl/crypto/x509/t_req.c',
+            'third_party/boringssl/crypto/x509/t_x509.c',
+            'third_party/boringssl/crypto/x509/t_x509a.c',
+            'third_party/boringssl/crypto/x509/x509.c',
+            'third_party/boringssl/crypto/x509/x509_att.c',
+            'third_party/boringssl/crypto/x509/x509_cmp.c',
+            'third_party/boringssl/crypto/x509/x509_d2.c',
+            'third_party/boringssl/crypto/x509/x509_def.c',
+            'third_party/boringssl/crypto/x509/x509_ext.c',
+            'third_party/boringssl/crypto/x509/x509_lu.c',
+            'third_party/boringssl/crypto/x509/x509_obj.c',
+            'third_party/boringssl/crypto/x509/x509_r2x.c',
+            'third_party/boringssl/crypto/x509/x509_req.c',
+            'third_party/boringssl/crypto/x509/x509_set.c',
+            'third_party/boringssl/crypto/x509/x509_trs.c',
+            'third_party/boringssl/crypto/x509/x509_txt.c',
+            'third_party/boringssl/crypto/x509/x509_v3.c',
+            'third_party/boringssl/crypto/x509/x509_vfy.c',
+            'third_party/boringssl/crypto/x509/x509_vpm.c',
+            'third_party/boringssl/crypto/x509/x509cset.c',
+            'third_party/boringssl/crypto/x509/x509name.c',
+            'third_party/boringssl/crypto/x509/x509rset.c',
+            'third_party/boringssl/crypto/x509/x509spki.c',
+            'third_party/boringssl/crypto/x509/x509type.c',
+            'third_party/boringssl/crypto/x509/x_algor.c',
+            'third_party/boringssl/crypto/x509/x_all.c',
+            'third_party/boringssl/crypto/x509/x_attrib.c',
+            'third_party/boringssl/crypto/x509/x_crl.c',
+            'third_party/boringssl/crypto/x509/x_exten.c',
+            'third_party/boringssl/crypto/x509/x_info.c',
+            'third_party/boringssl/crypto/x509/x_name.c',
+            'third_party/boringssl/crypto/x509/x_pkey.c',
+            'third_party/boringssl/crypto/x509/x_pubkey.c',
+            'third_party/boringssl/crypto/x509/x_req.c',
+            'third_party/boringssl/crypto/x509/x_sig.c',
+            'third_party/boringssl/crypto/x509/x_spki.c',
+            'third_party/boringssl/crypto/x509/x_val.c',
+            'third_party/boringssl/crypto/x509/x_x509.c',
+            'third_party/boringssl/crypto/x509/x_x509a.c',
+            'third_party/boringssl/crypto/x509v3/pcy_cache.c',
+            'third_party/boringssl/crypto/x509v3/pcy_data.c',
+            'third_party/boringssl/crypto/x509v3/pcy_lib.c',
+            'third_party/boringssl/crypto/x509v3/pcy_map.c',
+            'third_party/boringssl/crypto/x509v3/pcy_node.c',
+            'third_party/boringssl/crypto/x509v3/pcy_tree.c',
+            'third_party/boringssl/crypto/x509v3/v3_akey.c',
+            'third_party/boringssl/crypto/x509v3/v3_akeya.c',
+            'third_party/boringssl/crypto/x509v3/v3_alt.c',
+            'third_party/boringssl/crypto/x509v3/v3_bcons.c',
+            'third_party/boringssl/crypto/x509v3/v3_bitst.c',
+            'third_party/boringssl/crypto/x509v3/v3_conf.c',
+            'third_party/boringssl/crypto/x509v3/v3_cpols.c',
+            'third_party/boringssl/crypto/x509v3/v3_crld.c',
+            'third_party/boringssl/crypto/x509v3/v3_enum.c',
+            'third_party/boringssl/crypto/x509v3/v3_extku.c',
+            'third_party/boringssl/crypto/x509v3/v3_genn.c',
+            'third_party/boringssl/crypto/x509v3/v3_ia5.c',
+            'third_party/boringssl/crypto/x509v3/v3_info.c',
+            'third_party/boringssl/crypto/x509v3/v3_int.c',
+            'third_party/boringssl/crypto/x509v3/v3_lib.c',
+            'third_party/boringssl/crypto/x509v3/v3_ncons.c',
+            'third_party/boringssl/crypto/x509v3/v3_pci.c',
+            'third_party/boringssl/crypto/x509v3/v3_pcia.c',
+            'third_party/boringssl/crypto/x509v3/v3_pcons.c',
+            'third_party/boringssl/crypto/x509v3/v3_pku.c',
+            'third_party/boringssl/crypto/x509v3/v3_pmaps.c',
+            'third_party/boringssl/crypto/x509v3/v3_prn.c',
+            'third_party/boringssl/crypto/x509v3/v3_purp.c',
+            'third_party/boringssl/crypto/x509v3/v3_skey.c',
+            'third_party/boringssl/crypto/x509v3/v3_sxnet.c',
+            'third_party/boringssl/crypto/x509v3/v3_utl.c',
+            'third_party/boringssl/ssl/custom_extensions.c',
+            'third_party/boringssl/ssl/d1_both.c',
+            'third_party/boringssl/ssl/d1_clnt.c',
+            'third_party/boringssl/ssl/d1_lib.c',
+            'third_party/boringssl/ssl/d1_meth.c',
+            'third_party/boringssl/ssl/d1_pkt.c',
+            'third_party/boringssl/ssl/d1_srtp.c',
+            'third_party/boringssl/ssl/d1_srvr.c',
+            'third_party/boringssl/ssl/dtls_record.c',
+            'third_party/boringssl/ssl/pqueue/pqueue.c',
+            'third_party/boringssl/ssl/s3_both.c',
+            'third_party/boringssl/ssl/s3_clnt.c',
+            'third_party/boringssl/ssl/s3_enc.c',
+            'third_party/boringssl/ssl/s3_lib.c',
+            'third_party/boringssl/ssl/s3_meth.c',
+            'third_party/boringssl/ssl/s3_pkt.c',
+            'third_party/boringssl/ssl/s3_srvr.c',
+            'third_party/boringssl/ssl/ssl_aead_ctx.c',
+            'third_party/boringssl/ssl/ssl_asn1.c',
+            'third_party/boringssl/ssl/ssl_buffer.c',
+            'third_party/boringssl/ssl/ssl_cert.c',
+            'third_party/boringssl/ssl/ssl_cipher.c',
+            'third_party/boringssl/ssl/ssl_file.c',
+            'third_party/boringssl/ssl/ssl_lib.c',
+            'third_party/boringssl/ssl/ssl_rsa.c',
+            'third_party/boringssl/ssl/ssl_session.c',
+            'third_party/boringssl/ssl/ssl_stat.c',
+            'third_party/boringssl/ssl/t1_enc.c',
+            'third_party/boringssl/ssl/t1_lib.c',
+            'third_party/boringssl/ssl/tls_record.c',
+          ],
+          "include_dirs": [ "third_party/boringssl/include" ]
+        },
+        {
+          'cflags': [
+            '-std=c99',
+            '-Wall',
+            '-Werror'
+          ],
+          'target_name': 'z',
+          'product_prefix': 'lib',
+          'type': 'static_library',
+          'dependencies': [
+          ],
+          'sources': [
+            'third_party/zlib/adler32.c',
+            'third_party/zlib/compress.c',
+            'third_party/zlib/crc32.c',
+            'third_party/zlib/deflate.c',
+            'third_party/zlib/gzclose.c',
+            'third_party/zlib/gzlib.c',
+            'third_party/zlib/gzread.c',
+            'third_party/zlib/gzwrite.c',
+            'third_party/zlib/infback.c',
+            'third_party/zlib/inffast.c',
+            'third_party/zlib/inflate.c',
+            'third_party/zlib/inftrees.c',
+            'third_party/zlib/trees.c',
+            'third_party/zlib/uncompr.c',
+            'third_party/zlib/zutil.c',
+          ],
+          "include_dirs": [ "third_party/boringssl/include" ]
+        },
+      ]
+    }]
+  ],
   'targets': [
     {
       'cflags': [
@@ -147,7 +497,7 @@
             'MACOSX_DEPLOYMENT_TARGET': '10.9'
           }
         }]
-      ],
+      ]
     },
     {
       'cflags': [
@@ -321,7 +671,7 @@
             'MACOSX_DEPLOYMENT_TARGET': '10.9'
           }
         }]
-      ],
+      ]
     },
     {
       'include_dirs': [
@@ -340,13 +690,19 @@
         '-g'
       ],
       "conditions": [
-        ['OS == "mac"', {
+        ['OS=="mac"', {
           'xcode_settings': {
             'MACOSX_DEPLOYMENT_TARGET': '10.9',
             'OTHER_CFLAGS': [
               '-stdlib=libc++'
             ]
           }
+        }],
+        ['OS=="win"', {
+          'dependencies': [
+            "boringssl",
+            "z",
+          ]
         }]
       ],
       "target_name": "grpc_node",
@@ -367,5 +723,16 @@
         "gpr",
       ]
     },
+    {
+      "target_name": "action_after_build",
+      "type": "none",
+      "dependencies": [ "<(module_name)" ],
+      "copies": [
+        {
+          "files": [ "<(PRODUCT_DIR)/<(module_name).node"],
+          "destination": "<(module_path)"
+        }
+      ]
+    }
   ]
 }
diff --git a/build.yaml b/build.yaml
index 36b0310..3b02c38 100644
--- a/build.yaml
+++ b/build.yaml
@@ -2561,7 +2561,7 @@
       -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
     LDXX: clang++
     compile_the_world: true
-    timeout_multiplier: 1.5
+    timeout_multiplier: 2
   mutrace:
     CPPFLAGS: -O0
     DEFINES: _DEBUG DEBUG
@@ -2602,6 +2602,8 @@
 - deps:
   - grpc
   - gpr
+  - boringssl
+  - z
   headers:
   - src/node/ext/byte_buffer.h
   - src/node/ext/call.h
diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h
index 25eeb38..4e8776e 100644
--- a/include/grpc++/client_context.h
+++ b/include/grpc++/client_context.h
@@ -286,6 +286,7 @@
   /// a client context is constructed and destructed.
   class GlobalCallbacks {
    public:
+    virtual ~GlobalCallbacks() {}
     virtual void DefaultConstructor(ClientContext* context) = 0;
     virtual void Destructor(ClientContext* context) = 0;
   };
diff --git a/include/grpc++/server.h b/include/grpc++/server.h
index 644e66e..f24ed33 100644
--- a/include/grpc++/server.h
+++ b/include/grpc++/server.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -304,6 +304,8 @@
   int num_running_cb_;
   grpc::condition_variable callback_cv_;
 
+  std::shared_ptr<GlobalCallbacks> global_callbacks_;
+
   std::list<SyncRequest>* sync_methods_;
   std::unique_ptr<RpcServiceMethod> unknown_method_;
   bool has_generic_service_;
diff --git a/package.json b/package.json
index 0b87f6a..2abc266 100644
--- a/package.json
+++ b/package.json
@@ -22,12 +22,14 @@
     "lint": "node ./node_modules/jshint/bin/jshint src/node/src src/node/test src/node/interop src/node/index.js",
     "test": "./node_modules/.bin/mocha src/node/test && npm run-script lint",
     "gen_docs": "./node_modules/.bin/jsdoc -c src/node/jsdoc_conf.json",
-    "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha src/node/test"
+    "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha src/node/test",
+    "preinstall": "npm install node-pre-gyp",
+    "install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build"
   },
   "dependencies": {
-    "bindings": "^1.2.0",
     "lodash": "^3.9.3",
     "nan": "^2.0.0",
+    "node-pre-gyp": "^0.6.19",
     "protobufjs": "^4.0.0"
   },
   "devDependencies": {
@@ -45,6 +47,14 @@
   "engines": {
     "node": ">=0.10.13"
   },
+  "binary": {
+    "module_name": "grpc_node",
+    "module_path": "./build/Release/",
+    "host": "https://storage.googleapis.com/",
+    "remote_path": "grpc-precompiled-binaries/node/{name}/v{version}",
+    "package_name": "{node_abi}-{platform}-{arch}.tar.gz",
+    "module_path": "src/node/extension_binary"
+  },
   "files": [
     "LICENSE",
     "src/node/README.md",
@@ -365,6 +375,32 @@
     "src/core/census/operation.c",
     "src/core/census/tag_set.c",
     "src/core/census/tracing.c",
+    "third_party/zlib/crc32.h",
+    "third_party/zlib/deflate.h",
+    "third_party/zlib/gzguts.h",
+    "third_party/zlib/inffast.h",
+    "third_party/zlib/inffixed.h",
+    "third_party/zlib/inflate.h",
+    "third_party/zlib/inftrees.h",
+    "third_party/zlib/trees.h",
+    "third_party/zlib/zconf.h",
+    "third_party/zlib/zlib.h",
+    "third_party/zlib/zutil.h",
+    "third_party/zlib/adler32.c",
+    "third_party/zlib/compress.c",
+    "third_party/zlib/crc32.c",
+    "third_party/zlib/deflate.c",
+    "third_party/zlib/gzclose.c",
+    "third_party/zlib/gzlib.c",
+    "third_party/zlib/gzread.c",
+    "third_party/zlib/gzwrite.c",
+    "third_party/zlib/infback.c",
+    "third_party/zlib/inffast.c",
+    "third_party/zlib/inflate.c",
+    "third_party/zlib/inftrees.c",
+    "third_party/zlib/trees.c",
+    "third_party/zlib/uncompr.c",
+    "third_party/zlib/zutil.c",
     "include/grpc/support/alloc.h",
     "include/grpc/support/atm.h",
     "include/grpc/support/atm_gcc_atomic.h",
@@ -444,6 +480,407 @@
     "src/core/support/time_precise.c",
     "src/core/support/time_win32.c",
     "src/core/support/tls_pthread.c",
+    "third_party/boringssl/crypto/aes/internal.h",
+    "third_party/boringssl/crypto/asn1/asn1_locl.h",
+    "third_party/boringssl/crypto/bio/internal.h",
+    "third_party/boringssl/crypto/bn/internal.h",
+    "third_party/boringssl/crypto/bn/rsaz_exp.h",
+    "third_party/boringssl/crypto/bytestring/internal.h",
+    "third_party/boringssl/crypto/cipher/internal.h",
+    "third_party/boringssl/crypto/conf/conf_def.h",
+    "third_party/boringssl/crypto/conf/internal.h",
+    "third_party/boringssl/crypto/des/internal.h",
+    "third_party/boringssl/crypto/dh/internal.h",
+    "third_party/boringssl/crypto/digest/internal.h",
+    "third_party/boringssl/crypto/digest/md32_common.h",
+    "third_party/boringssl/crypto/directory.h",
+    "third_party/boringssl/crypto/dsa/internal.h",
+    "third_party/boringssl/crypto/ec/internal.h",
+    "third_party/boringssl/crypto/ec/p256-x86_64-table.h",
+    "third_party/boringssl/crypto/evp/internal.h",
+    "third_party/boringssl/crypto/internal.h",
+    "third_party/boringssl/crypto/modes/internal.h",
+    "third_party/boringssl/crypto/obj/obj_dat.h",
+    "third_party/boringssl/crypto/obj/obj_xref.h",
+    "third_party/boringssl/crypto/pkcs8/internal.h",
+    "third_party/boringssl/crypto/rand/internal.h",
+    "third_party/boringssl/crypto/rsa/internal.h",
+    "third_party/boringssl/crypto/test/scoped_types.h",
+    "third_party/boringssl/crypto/test/test_util.h",
+    "third_party/boringssl/crypto/x509/charmap.h",
+    "third_party/boringssl/crypto/x509/vpm_int.h",
+    "third_party/boringssl/crypto/x509v3/ext_dat.h",
+    "third_party/boringssl/crypto/x509v3/pcy_int.h",
+    "third_party/boringssl/include/openssl/aead.h",
+    "third_party/boringssl/include/openssl/aes.h",
+    "third_party/boringssl/include/openssl/arm_arch.h",
+    "third_party/boringssl/include/openssl/asn1.h",
+    "third_party/boringssl/include/openssl/asn1_mac.h",
+    "third_party/boringssl/include/openssl/asn1t.h",
+    "third_party/boringssl/include/openssl/base.h",
+    "third_party/boringssl/include/openssl/base64.h",
+    "third_party/boringssl/include/openssl/bio.h",
+    "third_party/boringssl/include/openssl/blowfish.h",
+    "third_party/boringssl/include/openssl/bn.h",
+    "third_party/boringssl/include/openssl/buf.h",
+    "third_party/boringssl/include/openssl/buffer.h",
+    "third_party/boringssl/include/openssl/bytestring.h",
+    "third_party/boringssl/include/openssl/cast.h",
+    "third_party/boringssl/include/openssl/chacha.h",
+    "third_party/boringssl/include/openssl/cipher.h",
+    "third_party/boringssl/include/openssl/cmac.h",
+    "third_party/boringssl/include/openssl/conf.h",
+    "third_party/boringssl/include/openssl/cpu.h",
+    "third_party/boringssl/include/openssl/crypto.h",
+    "third_party/boringssl/include/openssl/curve25519.h",
+    "third_party/boringssl/include/openssl/des.h",
+    "third_party/boringssl/include/openssl/dh.h",
+    "third_party/boringssl/include/openssl/digest.h",
+    "third_party/boringssl/include/openssl/dsa.h",
+    "third_party/boringssl/include/openssl/dtls1.h",
+    "third_party/boringssl/include/openssl/ec.h",
+    "third_party/boringssl/include/openssl/ec_key.h",
+    "third_party/boringssl/include/openssl/ecdh.h",
+    "third_party/boringssl/include/openssl/ecdsa.h",
+    "third_party/boringssl/include/openssl/engine.h",
+    "third_party/boringssl/include/openssl/err.h",
+    "third_party/boringssl/include/openssl/evp.h",
+    "third_party/boringssl/include/openssl/ex_data.h",
+    "third_party/boringssl/include/openssl/hkdf.h",
+    "third_party/boringssl/include/openssl/hmac.h",
+    "third_party/boringssl/include/openssl/lhash.h",
+    "third_party/boringssl/include/openssl/lhash_macros.h",
+    "third_party/boringssl/include/openssl/md4.h",
+    "third_party/boringssl/include/openssl/md5.h",
+    "third_party/boringssl/include/openssl/mem.h",
+    "third_party/boringssl/include/openssl/obj.h",
+    "third_party/boringssl/include/openssl/obj_mac.h",
+    "third_party/boringssl/include/openssl/objects.h",
+    "third_party/boringssl/include/openssl/opensslfeatures.h",
+    "third_party/boringssl/include/openssl/opensslv.h",
+    "third_party/boringssl/include/openssl/ossl_typ.h",
+    "third_party/boringssl/include/openssl/pem.h",
+    "third_party/boringssl/include/openssl/pkcs12.h",
+    "third_party/boringssl/include/openssl/pkcs7.h",
+    "third_party/boringssl/include/openssl/pkcs8.h",
+    "third_party/boringssl/include/openssl/poly1305.h",
+    "third_party/boringssl/include/openssl/pqueue.h",
+    "third_party/boringssl/include/openssl/rand.h",
+    "third_party/boringssl/include/openssl/rc4.h",
+    "third_party/boringssl/include/openssl/rsa.h",
+    "third_party/boringssl/include/openssl/safestack.h",
+    "third_party/boringssl/include/openssl/sha.h",
+    "third_party/boringssl/include/openssl/srtp.h",
+    "third_party/boringssl/include/openssl/ssl.h",
+    "third_party/boringssl/include/openssl/ssl3.h",
+    "third_party/boringssl/include/openssl/stack.h",
+    "third_party/boringssl/include/openssl/stack_macros.h",
+    "third_party/boringssl/include/openssl/thread.h",
+    "third_party/boringssl/include/openssl/time_support.h",
+    "third_party/boringssl/include/openssl/tls1.h",
+    "third_party/boringssl/include/openssl/type_check.h",
+    "third_party/boringssl/include/openssl/x509.h",
+    "third_party/boringssl/include/openssl/x509_vfy.h",
+    "third_party/boringssl/include/openssl/x509v3.h",
+    "third_party/boringssl/ssl/internal.h",
+    "third_party/boringssl/ssl/test/async_bio.h",
+    "third_party/boringssl/ssl/test/packeted_bio.h",
+    "third_party/boringssl/ssl/test/scoped_types.h",
+    "third_party/boringssl/ssl/test/test_config.h",
+    "src/boringssl/err_data.c",
+    "third_party/boringssl/crypto/aes/aes.c",
+    "third_party/boringssl/crypto/aes/mode_wrappers.c",
+    "third_party/boringssl/crypto/asn1/a_bitstr.c",
+    "third_party/boringssl/crypto/asn1/a_bool.c",
+    "third_party/boringssl/crypto/asn1/a_bytes.c",
+    "third_party/boringssl/crypto/asn1/a_d2i_fp.c",
+    "third_party/boringssl/crypto/asn1/a_dup.c",
+    "third_party/boringssl/crypto/asn1/a_enum.c",
+    "third_party/boringssl/crypto/asn1/a_gentm.c",
+    "third_party/boringssl/crypto/asn1/a_i2d_fp.c",
+    "third_party/boringssl/crypto/asn1/a_int.c",
+    "third_party/boringssl/crypto/asn1/a_mbstr.c",
+    "third_party/boringssl/crypto/asn1/a_object.c",
+    "third_party/boringssl/crypto/asn1/a_octet.c",
+    "third_party/boringssl/crypto/asn1/a_print.c",
+    "third_party/boringssl/crypto/asn1/a_strnid.c",
+    "third_party/boringssl/crypto/asn1/a_time.c",
+    "third_party/boringssl/crypto/asn1/a_type.c",
+    "third_party/boringssl/crypto/asn1/a_utctm.c",
+    "third_party/boringssl/crypto/asn1/a_utf8.c",
+    "third_party/boringssl/crypto/asn1/asn1_lib.c",
+    "third_party/boringssl/crypto/asn1/asn1_par.c",
+    "third_party/boringssl/crypto/asn1/asn_pack.c",
+    "third_party/boringssl/crypto/asn1/bio_asn1.c",
+    "third_party/boringssl/crypto/asn1/bio_ndef.c",
+    "third_party/boringssl/crypto/asn1/f_enum.c",
+    "third_party/boringssl/crypto/asn1/f_int.c",
+    "third_party/boringssl/crypto/asn1/f_string.c",
+    "third_party/boringssl/crypto/asn1/t_bitst.c",
+    "third_party/boringssl/crypto/asn1/t_pkey.c",
+    "third_party/boringssl/crypto/asn1/tasn_dec.c",
+    "third_party/boringssl/crypto/asn1/tasn_enc.c",
+    "third_party/boringssl/crypto/asn1/tasn_fre.c",
+    "third_party/boringssl/crypto/asn1/tasn_new.c",
+    "third_party/boringssl/crypto/asn1/tasn_prn.c",
+    "third_party/boringssl/crypto/asn1/tasn_typ.c",
+    "third_party/boringssl/crypto/asn1/tasn_utl.c",
+    "third_party/boringssl/crypto/asn1/x_bignum.c",
+    "third_party/boringssl/crypto/asn1/x_long.c",
+    "third_party/boringssl/crypto/base64/base64.c",
+    "third_party/boringssl/crypto/bio/bio.c",
+    "third_party/boringssl/crypto/bio/bio_mem.c",
+    "third_party/boringssl/crypto/bio/buffer.c",
+    "third_party/boringssl/crypto/bio/connect.c",
+    "third_party/boringssl/crypto/bio/fd.c",
+    "third_party/boringssl/crypto/bio/file.c",
+    "third_party/boringssl/crypto/bio/hexdump.c",
+    "third_party/boringssl/crypto/bio/pair.c",
+    "third_party/boringssl/crypto/bio/printf.c",
+    "third_party/boringssl/crypto/bio/socket.c",
+    "third_party/boringssl/crypto/bio/socket_helper.c",
+    "third_party/boringssl/crypto/bn/add.c",
+    "third_party/boringssl/crypto/bn/asm/x86_64-gcc.c",
+    "third_party/boringssl/crypto/bn/bn.c",
+    "third_party/boringssl/crypto/bn/bn_asn1.c",
+    "third_party/boringssl/crypto/bn/cmp.c",
+    "third_party/boringssl/crypto/bn/convert.c",
+    "third_party/boringssl/crypto/bn/ctx.c",
+    "third_party/boringssl/crypto/bn/div.c",
+    "third_party/boringssl/crypto/bn/exponentiation.c",
+    "third_party/boringssl/crypto/bn/gcd.c",
+    "third_party/boringssl/crypto/bn/generic.c",
+    "third_party/boringssl/crypto/bn/kronecker.c",
+    "third_party/boringssl/crypto/bn/montgomery.c",
+    "third_party/boringssl/crypto/bn/mul.c",
+    "third_party/boringssl/crypto/bn/prime.c",
+    "third_party/boringssl/crypto/bn/random.c",
+    "third_party/boringssl/crypto/bn/rsaz_exp.c",
+    "third_party/boringssl/crypto/bn/shift.c",
+    "third_party/boringssl/crypto/bn/sqrt.c",
+    "third_party/boringssl/crypto/buf/buf.c",
+    "third_party/boringssl/crypto/bytestring/ber.c",
+    "third_party/boringssl/crypto/bytestring/cbb.c",
+    "third_party/boringssl/crypto/bytestring/cbs.c",
+    "third_party/boringssl/crypto/chacha/chacha_generic.c",
+    "third_party/boringssl/crypto/chacha/chacha_vec.c",
+    "third_party/boringssl/crypto/cipher/aead.c",
+    "third_party/boringssl/crypto/cipher/cipher.c",
+    "third_party/boringssl/crypto/cipher/derive_key.c",
+    "third_party/boringssl/crypto/cipher/e_aes.c",
+    "third_party/boringssl/crypto/cipher/e_chacha20poly1305.c",
+    "third_party/boringssl/crypto/cipher/e_des.c",
+    "third_party/boringssl/crypto/cipher/e_null.c",
+    "third_party/boringssl/crypto/cipher/e_rc2.c",
+    "third_party/boringssl/crypto/cipher/e_rc4.c",
+    "third_party/boringssl/crypto/cipher/e_ssl3.c",
+    "third_party/boringssl/crypto/cipher/e_tls.c",
+    "third_party/boringssl/crypto/cipher/tls_cbc.c",
+    "third_party/boringssl/crypto/cmac/cmac.c",
+    "third_party/boringssl/crypto/conf/conf.c",
+    "third_party/boringssl/crypto/cpu-arm.c",
+    "third_party/boringssl/crypto/cpu-intel.c",
+    "third_party/boringssl/crypto/crypto.c",
+    "third_party/boringssl/crypto/curve25519/curve25519.c",
+    "third_party/boringssl/crypto/des/des.c",
+    "third_party/boringssl/crypto/dh/check.c",
+    "third_party/boringssl/crypto/dh/dh.c",
+    "third_party/boringssl/crypto/dh/dh_asn1.c",
+    "third_party/boringssl/crypto/dh/params.c",
+    "third_party/boringssl/crypto/digest/digest.c",
+    "third_party/boringssl/crypto/digest/digests.c",
+    "third_party/boringssl/crypto/directory_posix.c",
+    "third_party/boringssl/crypto/directory_win.c",
+    "third_party/boringssl/crypto/dsa/dsa.c",
+    "third_party/boringssl/crypto/dsa/dsa_asn1.c",
+    "third_party/boringssl/crypto/ec/ec.c",
+    "third_party/boringssl/crypto/ec/ec_asn1.c",
+    "third_party/boringssl/crypto/ec/ec_key.c",
+    "third_party/boringssl/crypto/ec/ec_montgomery.c",
+    "third_party/boringssl/crypto/ec/oct.c",
+    "third_party/boringssl/crypto/ec/p224-64.c",
+    "third_party/boringssl/crypto/ec/p256-64.c",
+    "third_party/boringssl/crypto/ec/p256-x86_64.c",
+    "third_party/boringssl/crypto/ec/simple.c",
+    "third_party/boringssl/crypto/ec/util-64.c",
+    "third_party/boringssl/crypto/ec/wnaf.c",
+    "third_party/boringssl/crypto/ecdh/ecdh.c",
+    "third_party/boringssl/crypto/ecdsa/ecdsa.c",
+    "third_party/boringssl/crypto/ecdsa/ecdsa_asn1.c",
+    "third_party/boringssl/crypto/engine/engine.c",
+    "third_party/boringssl/crypto/err/err.c",
+    "third_party/boringssl/crypto/evp/algorithm.c",
+    "third_party/boringssl/crypto/evp/digestsign.c",
+    "third_party/boringssl/crypto/evp/evp.c",
+    "third_party/boringssl/crypto/evp/evp_asn1.c",
+    "third_party/boringssl/crypto/evp/evp_ctx.c",
+    "third_party/boringssl/crypto/evp/p_dsa_asn1.c",
+    "third_party/boringssl/crypto/evp/p_ec.c",
+    "third_party/boringssl/crypto/evp/p_ec_asn1.c",
+    "third_party/boringssl/crypto/evp/p_rsa.c",
+    "third_party/boringssl/crypto/evp/p_rsa_asn1.c",
+    "third_party/boringssl/crypto/evp/pbkdf.c",
+    "third_party/boringssl/crypto/evp/sign.c",
+    "third_party/boringssl/crypto/ex_data.c",
+    "third_party/boringssl/crypto/hkdf/hkdf.c",
+    "third_party/boringssl/crypto/hmac/hmac.c",
+    "third_party/boringssl/crypto/lhash/lhash.c",
+    "third_party/boringssl/crypto/md4/md4.c",
+    "third_party/boringssl/crypto/md5/md5.c",
+    "third_party/boringssl/crypto/mem.c",
+    "third_party/boringssl/crypto/modes/cbc.c",
+    "third_party/boringssl/crypto/modes/cfb.c",
+    "third_party/boringssl/crypto/modes/ctr.c",
+    "third_party/boringssl/crypto/modes/gcm.c",
+    "third_party/boringssl/crypto/modes/ofb.c",
+    "third_party/boringssl/crypto/obj/obj.c",
+    "third_party/boringssl/crypto/obj/obj_xref.c",
+    "third_party/boringssl/crypto/pem/pem_all.c",
+    "third_party/boringssl/crypto/pem/pem_info.c",
+    "third_party/boringssl/crypto/pem/pem_lib.c",
+    "third_party/boringssl/crypto/pem/pem_oth.c",
+    "third_party/boringssl/crypto/pem/pem_pk8.c",
+    "third_party/boringssl/crypto/pem/pem_pkey.c",
+    "third_party/boringssl/crypto/pem/pem_x509.c",
+    "third_party/boringssl/crypto/pem/pem_xaux.c",
+    "third_party/boringssl/crypto/pkcs8/p5_pbe.c",
+    "third_party/boringssl/crypto/pkcs8/p5_pbev2.c",
+    "third_party/boringssl/crypto/pkcs8/p8_pkey.c",
+    "third_party/boringssl/crypto/pkcs8/pkcs8.c",
+    "third_party/boringssl/crypto/poly1305/poly1305.c",
+    "third_party/boringssl/crypto/poly1305/poly1305_arm.c",
+    "third_party/boringssl/crypto/poly1305/poly1305_vec.c",
+    "third_party/boringssl/crypto/rand/rand.c",
+    "third_party/boringssl/crypto/rand/urandom.c",
+    "third_party/boringssl/crypto/rand/windows.c",
+    "third_party/boringssl/crypto/rc4/rc4.c",
+    "third_party/boringssl/crypto/refcount_c11.c",
+    "third_party/boringssl/crypto/refcount_lock.c",
+    "third_party/boringssl/crypto/rsa/blinding.c",
+    "third_party/boringssl/crypto/rsa/padding.c",
+    "third_party/boringssl/crypto/rsa/rsa.c",
+    "third_party/boringssl/crypto/rsa/rsa_asn1.c",
+    "third_party/boringssl/crypto/rsa/rsa_impl.c",
+    "third_party/boringssl/crypto/sha/sha1.c",
+    "third_party/boringssl/crypto/sha/sha256.c",
+    "third_party/boringssl/crypto/sha/sha512.c",
+    "third_party/boringssl/crypto/stack/stack.c",
+    "third_party/boringssl/crypto/thread.c",
+    "third_party/boringssl/crypto/thread_none.c",
+    "third_party/boringssl/crypto/thread_pthread.c",
+    "third_party/boringssl/crypto/thread_win.c",
+    "third_party/boringssl/crypto/time_support.c",
+    "third_party/boringssl/crypto/x509/a_digest.c",
+    "third_party/boringssl/crypto/x509/a_sign.c",
+    "third_party/boringssl/crypto/x509/a_strex.c",
+    "third_party/boringssl/crypto/x509/a_verify.c",
+    "third_party/boringssl/crypto/x509/asn1_gen.c",
+    "third_party/boringssl/crypto/x509/by_dir.c",
+    "third_party/boringssl/crypto/x509/by_file.c",
+    "third_party/boringssl/crypto/x509/i2d_pr.c",
+    "third_party/boringssl/crypto/x509/pkcs7.c",
+    "third_party/boringssl/crypto/x509/t_crl.c",
+    "third_party/boringssl/crypto/x509/t_req.c",
+    "third_party/boringssl/crypto/x509/t_x509.c",
+    "third_party/boringssl/crypto/x509/t_x509a.c",
+    "third_party/boringssl/crypto/x509/x509.c",
+    "third_party/boringssl/crypto/x509/x509_att.c",
+    "third_party/boringssl/crypto/x509/x509_cmp.c",
+    "third_party/boringssl/crypto/x509/x509_d2.c",
+    "third_party/boringssl/crypto/x509/x509_def.c",
+    "third_party/boringssl/crypto/x509/x509_ext.c",
+    "third_party/boringssl/crypto/x509/x509_lu.c",
+    "third_party/boringssl/crypto/x509/x509_obj.c",
+    "third_party/boringssl/crypto/x509/x509_r2x.c",
+    "third_party/boringssl/crypto/x509/x509_req.c",
+    "third_party/boringssl/crypto/x509/x509_set.c",
+    "third_party/boringssl/crypto/x509/x509_trs.c",
+    "third_party/boringssl/crypto/x509/x509_txt.c",
+    "third_party/boringssl/crypto/x509/x509_v3.c",
+    "third_party/boringssl/crypto/x509/x509_vfy.c",
+    "third_party/boringssl/crypto/x509/x509_vpm.c",
+    "third_party/boringssl/crypto/x509/x509cset.c",
+    "third_party/boringssl/crypto/x509/x509name.c",
+    "third_party/boringssl/crypto/x509/x509rset.c",
+    "third_party/boringssl/crypto/x509/x509spki.c",
+    "third_party/boringssl/crypto/x509/x509type.c",
+    "third_party/boringssl/crypto/x509/x_algor.c",
+    "third_party/boringssl/crypto/x509/x_all.c",
+    "third_party/boringssl/crypto/x509/x_attrib.c",
+    "third_party/boringssl/crypto/x509/x_crl.c",
+    "third_party/boringssl/crypto/x509/x_exten.c",
+    "third_party/boringssl/crypto/x509/x_info.c",
+    "third_party/boringssl/crypto/x509/x_name.c",
+    "third_party/boringssl/crypto/x509/x_pkey.c",
+    "third_party/boringssl/crypto/x509/x_pubkey.c",
+    "third_party/boringssl/crypto/x509/x_req.c",
+    "third_party/boringssl/crypto/x509/x_sig.c",
+    "third_party/boringssl/crypto/x509/x_spki.c",
+    "third_party/boringssl/crypto/x509/x_val.c",
+    "third_party/boringssl/crypto/x509/x_x509.c",
+    "third_party/boringssl/crypto/x509/x_x509a.c",
+    "third_party/boringssl/crypto/x509v3/pcy_cache.c",
+    "third_party/boringssl/crypto/x509v3/pcy_data.c",
+    "third_party/boringssl/crypto/x509v3/pcy_lib.c",
+    "third_party/boringssl/crypto/x509v3/pcy_map.c",
+    "third_party/boringssl/crypto/x509v3/pcy_node.c",
+    "third_party/boringssl/crypto/x509v3/pcy_tree.c",
+    "third_party/boringssl/crypto/x509v3/v3_akey.c",
+    "third_party/boringssl/crypto/x509v3/v3_akeya.c",
+    "third_party/boringssl/crypto/x509v3/v3_alt.c",
+    "third_party/boringssl/crypto/x509v3/v3_bcons.c",
+    "third_party/boringssl/crypto/x509v3/v3_bitst.c",
+    "third_party/boringssl/crypto/x509v3/v3_conf.c",
+    "third_party/boringssl/crypto/x509v3/v3_cpols.c",
+    "third_party/boringssl/crypto/x509v3/v3_crld.c",
+    "third_party/boringssl/crypto/x509v3/v3_enum.c",
+    "third_party/boringssl/crypto/x509v3/v3_extku.c",
+    "third_party/boringssl/crypto/x509v3/v3_genn.c",
+    "third_party/boringssl/crypto/x509v3/v3_ia5.c",
+    "third_party/boringssl/crypto/x509v3/v3_info.c",
+    "third_party/boringssl/crypto/x509v3/v3_int.c",
+    "third_party/boringssl/crypto/x509v3/v3_lib.c",
+    "third_party/boringssl/crypto/x509v3/v3_ncons.c",
+    "third_party/boringssl/crypto/x509v3/v3_pci.c",
+    "third_party/boringssl/crypto/x509v3/v3_pcia.c",
+    "third_party/boringssl/crypto/x509v3/v3_pcons.c",
+    "third_party/boringssl/crypto/x509v3/v3_pku.c",
+    "third_party/boringssl/crypto/x509v3/v3_pmaps.c",
+    "third_party/boringssl/crypto/x509v3/v3_prn.c",
+    "third_party/boringssl/crypto/x509v3/v3_purp.c",
+    "third_party/boringssl/crypto/x509v3/v3_skey.c",
+    "third_party/boringssl/crypto/x509v3/v3_sxnet.c",
+    "third_party/boringssl/crypto/x509v3/v3_utl.c",
+    "third_party/boringssl/ssl/custom_extensions.c",
+    "third_party/boringssl/ssl/d1_both.c",
+    "third_party/boringssl/ssl/d1_clnt.c",
+    "third_party/boringssl/ssl/d1_lib.c",
+    "third_party/boringssl/ssl/d1_meth.c",
+    "third_party/boringssl/ssl/d1_pkt.c",
+    "third_party/boringssl/ssl/d1_srtp.c",
+    "third_party/boringssl/ssl/d1_srvr.c",
+    "third_party/boringssl/ssl/dtls_record.c",
+    "third_party/boringssl/ssl/pqueue/pqueue.c",
+    "third_party/boringssl/ssl/s3_both.c",
+    "third_party/boringssl/ssl/s3_clnt.c",
+    "third_party/boringssl/ssl/s3_enc.c",
+    "third_party/boringssl/ssl/s3_lib.c",
+    "third_party/boringssl/ssl/s3_meth.c",
+    "third_party/boringssl/ssl/s3_pkt.c",
+    "third_party/boringssl/ssl/s3_srvr.c",
+    "third_party/boringssl/ssl/ssl_aead_ctx.c",
+    "third_party/boringssl/ssl/ssl_asn1.c",
+    "third_party/boringssl/ssl/ssl_buffer.c",
+    "third_party/boringssl/ssl/ssl_cert.c",
+    "third_party/boringssl/ssl/ssl_cipher.c",
+    "third_party/boringssl/ssl/ssl_file.c",
+    "third_party/boringssl/ssl/ssl_lib.c",
+    "third_party/boringssl/ssl/ssl_rsa.c",
+    "third_party/boringssl/ssl/ssl_session.c",
+    "third_party/boringssl/ssl/ssl_stat.c",
+    "third_party/boringssl/ssl/t1_enc.c",
+    "third_party/boringssl/ssl/t1_lib.c",
+    "third_party/boringssl/ssl/tls_record.c",
     "binding.gyp"
   ],
   "main": "src/node/index.js",
diff --git a/setup.py b/setup.py
index 52d3d22..01e9180 100644
--- a/setup.py
+++ b/setup.py
@@ -119,6 +119,7 @@
 }
 
 INSTALL_REQUIRES = (
+    'six>=1.10',
     'enum34>=1.0.4',
     'futures>=2.2.0',
     # TODO(atash): eventually split the grpcio package into a metapackage
@@ -131,6 +132,7 @@
 ) + INSTALL_REQUIRES
 
 COMMAND_CLASS = {
+    'install': commands.Install,
     'doc': commands.SphinxDocumentation,
     'build_proto_modules': commands.BuildProtoModules,
     'build_project_metadata': commands.BuildProjectMetadata,
@@ -138,6 +140,7 @@
     'build_ext': commands.BuildExt,
     'gather': commands.Gather,
     'run_interop': commands.RunInterop,
+    'bdist_egg_grpc_custom': commands.BdistEggCustomName,
 }
 
 # Ensure that package data is copied over before any commands have been run:
@@ -187,7 +190,7 @@
 
 setuptools.setup(
     name='grpcio',
-    version='0.12.0b5',
+    version='0.12.0b6',
     license=LICENSE,
     ext_modules=CYTHON_EXTENSION_MODULES,
     packages=list(PACKAGES),
diff --git a/src/core/census/initialize.c b/src/core/census/initialize.c
index b7af714..ce7ec09 100644
--- a/src/core/census/initialize.c
+++ b/src/core/census/initialize.c
@@ -37,9 +37,7 @@
 
 int census_initialize(int features) {
   if (features_enabled != CENSUS_FEATURE_NONE) {
-    return 1;
-  }
-  if (features == CENSUS_FEATURE_NONE) {
+    // Must have been a previous call to census_initialize; return error
     return 1;
   }
   features_enabled = features;
diff --git a/src/core/client_config/lb_policies/pick_first.c b/src/core/client_config/lb_policies/pick_first.c
index e6ddb1a..5b10600 100644
--- a/src/core/client_config/lb_policies/pick_first.c
+++ b/src/core/client_config/lb_policies/pick_first.c
@@ -76,7 +76,7 @@
 } pick_first_lb_policy;
 
 #define GET_SELECTED(p) \
-  ((grpc_connected_subchannel *)gpr_atm_no_barrier_load(&(p)->selected))
+  ((grpc_connected_subchannel *)gpr_atm_acq_load(&(p)->selected))
 
 void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
   pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
@@ -268,10 +268,10 @@
         selected =
             grpc_subchannel_get_connected_subchannel(selected_subchannel);
         GPR_ASSERT(selected != NULL);
-        gpr_atm_no_barrier_store(&p->selected, (gpr_atm)selected);
         GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked_first");
         /* drop the pick list: we are connected now */
         GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels");
+        gpr_atm_rel_store(&p->selected, (gpr_atm)selected);
         grpc_exec_ctx_enqueue(exec_ctx,
                               grpc_closure_create(destroy_subchannels, p), 1);
         /* update any calls that were waiting for a pick */
diff --git a/src/core/client_config/subchannel.c b/src/core/client_config/subchannel.c
index 2992da8..fccc1dd 100644
--- a/src/core/client_config/subchannel.c
+++ b/src/core/client_config/subchannel.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -284,9 +284,13 @@
   c->connector = connector;
   grpc_connector_ref(c->connector);
   c->num_filters = args->filter_count;
-  c->filters = gpr_malloc(sizeof(grpc_channel_filter *) * c->num_filters);
-  memcpy((void *)c->filters, args->filters,
-         sizeof(grpc_channel_filter *) * c->num_filters);
+  if (c->num_filters > 0) {
+    c->filters = gpr_malloc(sizeof(grpc_channel_filter *) * c->num_filters);
+    memcpy((void *)c->filters, args->filters,
+           sizeof(grpc_channel_filter *) * c->num_filters);
+  } else {
+    c->filters = NULL;
+  }
   c->addr = gpr_malloc(args->addr_len);
   memcpy(c->addr, args->addr, args->addr_len);
   grpc_pollset_set_init(&c->pollset_set);
@@ -483,7 +487,9 @@
   /* build final filter list */
   num_filters = c->num_filters + c->connecting_result.num_filters + 1;
   filters = gpr_malloc(sizeof(*filters) * num_filters);
-  memcpy((void *)filters, c->filters, sizeof(*filters) * c->num_filters);
+  if (c->num_filters > 0) {
+    memcpy((void *)filters, c->filters, sizeof(*filters) * c->num_filters);
+  }
   memcpy((void *)(filters + c->num_filters), c->connecting_result.filters,
          sizeof(*filters) * c->connecting_result.num_filters);
   filters[num_filters - 1] = &grpc_connected_channel_filter;
@@ -519,7 +525,12 @@
   }
 
   /* publish */
-  GPR_ASSERT(gpr_atm_no_barrier_cas(&c->connected_subchannel, 0, (gpr_atm)con));
+  /* TODO(ctiller): this full barrier seems to clear up a TSAN failure.
+                    I'd have expected the rel_cas below to be enough, but
+                    seemingly it's not.
+                    Re-evaluate if we really need this. */
+  gpr_atm_full_barrier();
+  GPR_ASSERT(gpr_atm_rel_cas(&c->connected_subchannel, 0, (gpr_atm)con));
   c->connecting = 0;
 
   /* setup subchannel watching connected subchannel for changes; subchannel ref
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index 2aa5328..710d7cb 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,7 @@
 class DefaultGlobalClientCallbacks GRPC_FINAL
     : public ClientContext::GlobalCallbacks {
  public:
+  ~DefaultGlobalClientCallbacks() GRPC_OVERRIDE {}
   void DefaultConstructor(ClientContext* context) GRPC_OVERRIDE {}
   void Destructor(ClientContext* context) GRPC_OVERRIDE {}
 };
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index 878775b..3bf9f3f 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -53,17 +53,17 @@
 
 class DefaultGlobalCallbacks GRPC_FINAL : public Server::GlobalCallbacks {
  public:
+  ~DefaultGlobalCallbacks() GRPC_OVERRIDE {}
   void PreSynchronousRequest(ServerContext* context) GRPC_OVERRIDE {}
   void PostSynchronousRequest(ServerContext* context) GRPC_OVERRIDE {}
 };
 
-static Server::GlobalCallbacks* g_callbacks = nullptr;
+static std::shared_ptr<Server::GlobalCallbacks> g_callbacks = nullptr;
 static gpr_once g_once_init_callbacks = GPR_ONCE_INIT;
 
 static void InitGlobalCallbacks() {
   if (g_callbacks == nullptr) {
-    static DefaultGlobalCallbacks default_global_callbacks;
-    g_callbacks = &default_global_callbacks;
+    g_callbacks.reset(new DefaultGlobalCallbacks());
   }
 }
 
@@ -234,12 +234,12 @@
       }
     }
 
-    void Run() {
+    void Run(std::shared_ptr<GlobalCallbacks> global_callbacks) {
       ctx_.BeginCompletionOp(&call_);
-      g_callbacks->PreSynchronousRequest(&ctx_);
+      global_callbacks->PreSynchronousRequest(&ctx_);
       method_->handler()->RunHandler(MethodHandler::HandlerParameter(
           &call_, &ctx_, request_payload_, call_.max_message_size()));
-      g_callbacks->PostSynchronousRequest(&ctx_);
+      global_callbacks->PostSynchronousRequest(&ctx_);
       request_payload_ = nullptr;
       void* ignored_tag;
       bool ignored_ok;
@@ -287,6 +287,7 @@
       thread_pool_(thread_pool),
       thread_pool_owned_(thread_pool_owned) {
   gpr_once_init(&g_once_init_callbacks, InitGlobalCallbacks);
+  global_callbacks_ = g_callbacks;
   grpc_server_register_completion_queue(server_, cq_.cq(), nullptr);
 }
 
@@ -311,7 +312,7 @@
 void Server::SetGlobalCallbacks(GlobalCallbacks* callbacks) {
   GPR_ASSERT(g_callbacks == nullptr);
   GPR_ASSERT(callbacks != nullptr);
-  g_callbacks = callbacks;
+  g_callbacks.reset(callbacks);
 }
 
 bool Server::RegisterService(const grpc::string* host, RpcService* service) {
@@ -569,7 +570,7 @@
         }
       }
       GPR_TIMER_SCOPE("cd.Run()", 0);
-      cd.Run();
+      cd.Run(global_callbacks_);
     }
   }
 
diff --git a/src/cpp/util/byte_buffer.cc b/src/cpp/util/byte_buffer.cc
index 2952f94..3a2318d 100644
--- a/src/cpp/util/byte_buffer.cc
+++ b/src/cpp/util/byte_buffer.cc
@@ -31,8 +31,8 @@
  *
  */
 
-#include <grpc/byte_buffer_reader.h>
 #include <grpc++/support/byte_buffer.h>
+#include <grpc/byte_buffer_reader.h>
 
 namespace grpc {
 
@@ -84,8 +84,10 @@
     : buffer_(grpc_byte_buffer_copy(buf.buffer_)) {}
 
 ByteBuffer& ByteBuffer::operator=(const ByteBuffer& buf) {
-  Clear();                                       // first remove existing data
-  buffer_ = grpc_byte_buffer_copy(buf.buffer_);  // then copy
+  Clear();  // first remove existing data
+  if (buf.buffer_) {
+    buffer_ = grpc_byte_buffer_copy(buf.buffer_);  // then copy
+  }
   return *this;
 }
 
diff --git a/src/node/ext/byte_buffer.cc b/src/node/ext/byte_buffer.cc
index c306292..ee703fd 100644
--- a/src/node/ext/byte_buffer.cc
+++ b/src/node/ext/byte_buffer.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -69,7 +69,7 @@
     return scope.Escape(Nan::Null());
   }
   size_t length = grpc_byte_buffer_length(buffer);
-  char *result = reinterpret_cast<char *>(calloc(length, sizeof(char)));
+  char *result = new char[length];
   size_t offset = 0;
   grpc_byte_buffer_reader reader;
   grpc_byte_buffer_reader_init(&reader, buffer);
diff --git a/src/node/index.js b/src/node/index.js
index 0d1a7fd..7eacdc6 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -51,7 +51,7 @@
 
 var Metadata = require('./src/metadata.js');
 
-var grpc = require('bindings')('grpc_node');
+var grpc = require('./src/grpc_extension');
 
 /**
  * Load a gRPC object from an existing ProtoBuf.Reflect object.
diff --git a/src/node/src/client.js b/src/node/src/client.js
index d578267..b5247a6 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -51,7 +51,7 @@
 
 var _ = require('lodash');
 
-var grpc = require('bindings')('grpc_node');
+var grpc = require('./grpc_extension');
 
 var common = require('./common');
 
diff --git a/src/node/src/credentials.js b/src/node/src/credentials.js
index dcbfac1..710ab6d 100644
--- a/src/node/src/credentials.js
+++ b/src/node/src/credentials.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -61,7 +61,7 @@
 
 'use strict';
 
-var grpc = require('bindings')('grpc_node.node');
+var grpc = require('./grpc_extension');
 
 var CallCredentials = grpc.CallCredentials;
 
diff --git a/src/node/src/grpc_extension.js b/src/node/src/grpc_extension.js
new file mode 100644
index 0000000..d4eca65
--- /dev/null
+++ b/src/node/src/grpc_extension.js
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+var binary = require('node-pre-gyp');
+var path = require('path');
+var binding_path = binary.find(path.resolve(
+    path.join(__dirname,'../../../package.json')));
+var binding = require(binding_path);
+
+module.exports = binding;
diff --git a/src/node/src/metadata.js b/src/node/src/metadata.js
index fef79f9..51a9f8a 100644
--- a/src/node/src/metadata.js
+++ b/src/node/src/metadata.js
@@ -49,7 +49,7 @@
 
 var _ = require('lodash');
 
-var grpc = require('bindings')('grpc_node');
+var grpc = require('./grpc_extension');
 
 /**
  * Class for storing metadata. Keys are normalized to lowercase ASCII.
diff --git a/src/node/src/server.js b/src/node/src/server.js
index ceaa9f5..e5aadcd 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -51,7 +51,7 @@
 
 var _ = require('lodash');
 
-var grpc = require('bindings')('grpc_node');
+var grpc = require('./grpc_extension');
 
 var common = require('./common');
 
diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js
index f1f86b3..2300096 100644
--- a/src/node/test/call_test.js
+++ b/src/node/test/call_test.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,7 @@
 'use strict';
 
 var assert = require('assert');
-var grpc = require('bindings')('grpc_node');
+var grpc = require('../src/grpc_extension');
 
 /**
  * Helper function to return an absolute deadline given a relative timeout in
diff --git a/src/node/test/channel_test.js b/src/node/test/channel_test.js
index 7163a5f..c0ae2b7 100644
--- a/src/node/test/channel_test.js
+++ b/src/node/test/channel_test.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,7 @@
 'use strict';
 
 var assert = require('assert');
-var grpc = require('bindings')('grpc_node');
+var grpc = require('../src/grpc_extension');
 
 /**
  * This is used for testing functions with multiple asynchronous calls that
diff --git a/src/node/test/constant_test.js b/src/node/test/constant_test.js
index b17cd33..712c707 100644
--- a/src/node/test/constant_test.js
+++ b/src/node/test/constant_test.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,7 @@
 'use strict';
 
 var assert = require('assert');
-var grpc = require('bindings')('grpc_node');
+var grpc = require('../src/grpc_extension');
 
 /**
  * List of all status names
diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js
index 0f6c594..353c6c7 100644
--- a/src/node/test/end_to_end_test.js
+++ b/src/node/test/end_to_end_test.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,7 @@
 'use strict';
 
 var assert = require('assert');
-var grpc = require('bindings')('grpc_node');
+var grpc = require('../src/grpc_extension');
 
 /**
  * This is used for testing functions with multiple asynchronous calls that
diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js
index 592f47e..71a9647 100644
--- a/src/node/test/server_test.js
+++ b/src/node/test/server_test.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,7 +36,7 @@
 var assert = require('assert');
 var fs = require('fs');
 var path = require('path');
-var grpc = require('bindings')('grpc_node');
+var grpc = require('../src/grpc_extension');
 
 describe('server', function() {
   describe('constructor', function() {
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index fc765ed..c65d95f 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -952,6 +952,7 @@
   describe('Cancellation', function() {
     it('With a unary call', function(done) {
       done = multiDone(done, 2);
+      var call;
       proxy_impl.unary = function(parent, callback) {
         client.unary(parent.request, function(err, value) {
           try {
@@ -969,12 +970,13 @@
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
                                     grpc.credentials.createInsecure());
-      var call = proxy_client.unary({}, function(err, value) {
+      call = proxy_client.unary({}, function(err, value) {
         done();
       });
     });
     it('With a client stream call', function(done) {
       done = multiDone(done, 2);
+      var call;
       proxy_impl.clientStream = function(parent, callback) {
         client.clientStream(function(err, value) {
           try {
@@ -992,12 +994,13 @@
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
                                     grpc.credentials.createInsecure());
-      var call = proxy_client.clientStream(function(err, value) {
+      call = proxy_client.clientStream(function(err, value) {
         done();
       });
     });
     it('With a server stream call', function(done) {
       done = multiDone(done, 2);
+      var call;
       proxy_impl.serverStream = function(parent) {
         var child = client.serverStream(parent.request, null,
                                         {parent: parent});
@@ -1013,13 +1016,14 @@
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
                                     grpc.credentials.createInsecure());
-      var call = proxy_client.serverStream({});
+      call = proxy_client.serverStream({});
       call.on('error', function(err) {
         done();
       });
     });
     it('With a bidi stream call', function(done) {
       done = multiDone(done, 2);
+      var call;
       proxy_impl.bidiStream = function(parent) {
         var child = client.bidiStream(null, {parent: parent});
         child.on('error', function(err) {
@@ -1034,7 +1038,7 @@
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
                                     grpc.credentials.createInsecure());
-      var call = proxy_client.bidiStream();
+      call = proxy_client.bidiStream();
       call.on('error', function(err) {
         done();
       });
diff --git a/src/proto/grpc/testing/control.proto b/src/proto/grpc/testing/control.proto
index 0784ebf..7ba6f98 100644
--- a/src/proto/grpc/testing/control.proto
+++ b/src/proto/grpc/testing/control.proto
@@ -1,4 +1,4 @@
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,7 @@
 enum ServerType {
   SYNC_SERVER = 0;
   ASYNC_SERVER = 1;
+  ASYNC_GENERIC_SERVER = 2;
 }
 
 enum RpcType {
diff --git a/src/proto/grpc/testing/echo_messages.proto b/src/proto/grpc/testing/echo_messages.proto
index f01d645..d05a355 100644
--- a/src/proto/grpc/testing/echo_messages.proto
+++ b/src/proto/grpc/testing/echo_messages.proto
@@ -1,5 +1,5 @@
 
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
@@ -41,6 +41,7 @@
   int32 response_message_length = 6;
   bool echo_peer = 7;
   string expected_client_identity = 8; // will force check_auth_context.
+  bool skip_cancelled_check = 9;
 }
 
 message EchoRequest {
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index 29b506a..a6b8ad3 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -30,15 +30,22 @@
 """Provides distutils command classes for the GRPC Python setup process."""
 
 import distutils
+import glob
 import os
 import os.path
+import platform
 import re
+import shutil
 import subprocess
 import sys
+import traceback
 
 import setuptools
+from setuptools.command import bdist_egg
 from setuptools.command import build_ext
 from setuptools.command import build_py
+from setuptools.command import easy_install
+from setuptools.command import install
 from setuptools.command import test
 
 import support
@@ -58,6 +65,129 @@
   """Simple exception class for GRPC custom commands."""
 
 
+# TODO(atash): Remove this once PyPI has better Linux bdist support. See
+# https://bitbucket.org/pypa/pypi/issues/120/binary-wheels-for-linux-are-not-supported
+def _get_linux_bdist_egg(decorated_basename, target_egg_basename):
+  """Returns a string path to a .egg file for Linux to install.
+
+  If we can retrieve a pre-compiled egg from online, uses it. Else, emits a
+  warning and builds from source.
+  """
+  # Break import style to ensure that setup.py has had a chance to install the
+  # relevant package eggs.
+  from six.moves.urllib import request
+  decorated_path = decorated_basename + '.egg'
+  try:
+    url = (
+        'https://storage.googleapis.com/grpc-precompiled-binaries/'
+        'python/{target}'
+            .format(target=decorated_path))
+    egg_data = request.urlopen(url).read()
+  except IOError as error:
+    raise CommandError(
+        '{}\n\nCould not find the bdist egg {}: {}'
+            .format(traceback.format_exc(), decorated_path, error.message))
+  # Our chosen local egg path.
+  egg_path = target_egg_basename + '.egg'
+  try:
+    with open(egg_path, 'w') as egg_file:
+      egg_file.write(egg_data)
+  except IOError as error:
+    raise CommandError(
+        '{}\n\nCould not write grpcio egg: {}'
+            .format(traceback.format_exc(), error.message))
+  return egg_path
+
+
+class EggNameMixin(object):
+
+  def egg_name(self, with_custom):
+    """
+    Args:
+      with_custom: Boolean describing whether or not to decorate the egg name
+        with custom gRPC-specific target information.
+    """
+    egg_command = self.get_finalized_command('bdist_egg')
+    base = os.path.splitext(os.path.basename(egg_command.egg_output))[0]
+    if with_custom:
+      flavor = 'ucs2' if sys.maxunicode == 65535 else 'ucs4'
+      return '{base}-{flavor}'.format(base=base, flavor=flavor)
+    else:
+      return base
+
+
+class Install(install.install, EggNameMixin):
+  """Custom Install command for gRPC Python.
+
+  This is for bdist shims and whatever else we might need a custom install
+  command for.
+  """
+
+  user_options = install.install.user_options + [
+      # TODO(atash): remove this once manylinux gets on PyPI. See
+      # https://bitbucket.org/pypa/pypi/issues/120/binary-wheels-for-linux-are-not-supported
+      ('use-linux-bdist', None,
+       'Whether to retrieve a binary for Linux instead of building from '
+       'source.'),
+  ]
+
+  def initialize_options(self):
+    install.install.initialize_options(self)
+    self.use_linux_bdist = False
+
+  def finalize_options(self):
+    install.install.finalize_options(self)
+
+  def run(self):
+    if self.use_linux_bdist:
+      try:
+        egg_path = _get_linux_bdist_egg(self.egg_name(True),
+                                        self.egg_name(False))
+      except CommandError as error:
+        sys.stderr.write(
+            '\nWARNING: Failed to acquire grpcio prebuilt binary:\n'
+            '{}.\n\n'.format(error.message))
+        raise
+      try:
+        self._run_bdist_retrieval_install(egg_path)
+      except Exception as error:
+        # if anything else happens (and given how there's no way to really know
+        # what's happening in setuptools here, I mean *anything*), warn the user
+        # and fall back to building from source.
+        sys.stderr.write(
+            '{}\nWARNING: Failed to install grpcio prebuilt binary.\n\n'
+                .format(traceback.format_exc()))
+        install.install.run(self)
+    else:
+      install.install.run(self)
+
+  # TODO(atash): Remove this once PyPI has better Linux bdist support. See
+  # https://bitbucket.org/pypa/pypi/issues/120/binary-wheels-for-linux-are-not-supported
+  def _run_bdist_retrieval_install(self, bdist_egg):
+    easy_install = self.distribution.get_command_class('easy_install')
+    easy_install_command = easy_install(
+        self.distribution, args='x', root=self.root, record=self.record,
+    )
+    easy_install_command.ensure_finalized()
+    easy_install_command.always_copy_from = '.'
+    easy_install_command.package_index.scan(glob.glob('*.egg'))
+    arguments = [bdist_egg]
+    if setuptools.bootstrap_install_from:
+      args.insert(0, setuptools.bootstrap_install_from)
+    easy_install_command.args = arguments
+    easy_install_command.run()
+    setuptools.bootstrap_install_from = None
+
+
+class BdistEggCustomName(bdist_egg.bdist_egg, EggNameMixin):
+  """Thin wrapper around the bdist_egg command to build with our custom name."""
+
+  def run(self):
+    bdist_egg.bdist_egg.run(self)
+    target = os.path.join(self.dist_dir, '{}.egg'.format(self.egg_name(True)))
+    shutil.move(self.get_outputs()[0], target)
+
+
 class SphinxDocumentation(setuptools.Command):
   """Command to generate documentation via sphinx."""
 
diff --git a/src/python/grpcio/grpc/framework/foundation/logging_pool.py b/src/python/grpcio/grpc/framework/foundation/logging_pool.py
index 7c7a6ee..f82c7f7 100644
--- a/src/python/grpcio/grpc/framework/foundation/logging_pool.py
+++ b/src/python/grpcio/grpc/framework/foundation/logging_pool.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,6 @@
 
 """A thread pool that logs exceptions raised by tasks executed within it."""
 
-import functools
 import logging
 
 from concurrent import futures
@@ -37,12 +36,12 @@
 
 def _wrap(behavior):
   """Wraps an arbitrary callable behavior in exception-logging."""
-  @functools.wraps(behavior)
   def _wrapping(*args, **kwargs):
     try:
       return behavior(*args, **kwargs)
     except Exception as e:
-      logging.exception('Unexpected exception from task run in logging pool!')
+      logging.exception(
+          'Unexpected exception from %s executed in logging pool!', behavior)
       raise
   return _wrapping
 
diff --git a/src/python/grpcio/tests/unit/framework/foundation/_logging_pool_test.py b/src/python/grpcio/tests/unit/framework/foundation/_logging_pool_test.py
index 452802d..0521e1c 100644
--- a/src/python/grpcio/tests/unit/framework/foundation/_logging_pool_test.py
+++ b/src/python/grpcio/tests/unit/framework/foundation/_logging_pool_test.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,6 +29,7 @@
 
 """Tests for grpc.framework.foundation.logging_pool."""
 
+import threading
 import unittest
 
 from grpc.framework.foundation import logging_pool
@@ -36,6 +37,21 @@
 _POOL_SIZE = 16
 
 
+class _CallableObject(object):
+
+  def __init__(self):
+    self._lock = threading.Lock()
+    self._passed_values = []
+
+  def __call__(self, value):
+    with self._lock:
+      self._passed_values.append(value)
+
+  def passed_values(self):
+    with self._lock:
+      return tuple(self._passed_values)
+
+
 class LoggingPoolTest(unittest.TestCase):
 
   def testUpAndDown(self):
@@ -59,6 +75,14 @@
 
     self.assertIsNotNone(raised_exception)
 
+  def testCallableObjectExecuted(self):
+    callable_object = _CallableObject()
+    passed_object = object()
+    with logging_pool.pool(_POOL_SIZE) as pool:
+      future = pool.submit(callable_object, passed_object)
+    self.assertIsNone(future.result())
+    self.assertSequenceEqual((passed_object,), callable_object.passed_values())
+
 
 if __name__ == '__main__':
   unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py
index 3bcefa6..c8a3a1b 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -30,9 +30,12 @@
 """Test code for the Face layer of RPC Framework."""
 
 import abc
+import itertools
 import unittest
+from concurrent import futures
 
 # test_interfaces is referenced from specification in this module.
+from grpc.framework.foundation import logging_pool
 from grpc.framework.interfaces.face import face
 from tests.unit.framework.common import test_constants
 from tests.unit.framework.common import test_control
@@ -139,13 +142,50 @@
 
         test_messages.verify(second_request, second_response, self)
 
-  @unittest.skip('Parallel invocations impossible with blocking control flow!')
   def testParallelInvocations(self):
-    raise NotImplementedError()
+    pool = logging_pool.pool(test_constants.PARALLELISM)
+    for (group, method), test_messages_sequence in (
+        self._digest.unary_unary_messages_sequences.iteritems()):
+      for test_messages in test_messages_sequence:
+        requests = []
+        response_futures = []
+        for _ in range(test_constants.PARALLELISM):
+          request = test_messages.request()
+          response_future = pool.submit(
+              self._invoker.blocking(group, method), request,
+              test_constants.LONG_TIMEOUT)
+          requests.append(request)
+          response_futures.append(response_future)
 
-  @unittest.skip('Parallel invocations impossible with blocking control flow!')
+        responses = [
+            response_future.result() for response_future in response_futures]
+
+        for request, response in zip(requests, responses):
+          test_messages.verify(request, response, self)
+    pool.shutdown(wait=True)
+
   def testWaitingForSomeButNotAllParallelInvocations(self):
-    raise NotImplementedError()
+    pool = logging_pool.pool(test_constants.PARALLELISM)
+    for (group, method), test_messages_sequence in (
+        self._digest.unary_unary_messages_sequences.iteritems()):
+      for test_messages in test_messages_sequence:
+        requests = []
+        response_futures_to_indices = {}
+        for index in range(test_constants.PARALLELISM):
+          request = test_messages.request()
+          response_future = pool.submit(
+              self._invoker.blocking(group, method), request,
+              test_constants.LONG_TIMEOUT)
+          requests.append(request)
+          response_futures_to_indices[response_future] = index
+
+        some_completed_response_futures_iterator = itertools.islice(
+            futures.as_completed(response_futures_to_indices),
+            test_constants.PARALLELISM / 2)
+        for response_future in some_completed_response_futures_iterator:
+          index = response_futures_to_indices[response_future]
+          test_messages.verify(requests[index], response_future.result(), self)
+    pool.shutdown(wait=True)
 
   @unittest.skip('Cancellation impossible with blocking control flow!')
   def testCancelledUnaryRequestUnaryResponse(self):
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
index fc8daa9..1d36a93 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
@@ -31,8 +31,10 @@
 
 import abc
 import contextlib
+import itertools
 import threading
 import unittest
+from concurrent import futures
 
 # test_interfaces is referenced from specification in this module.
 from grpc.framework.foundation import logging_pool
@@ -219,6 +221,23 @@
 
         test_messages.verify(second_request, second_response, self)
 
+  def testParallelInvocations(self):
+    for (group, method), test_messages_sequence in (
+        self._digest.unary_unary_messages_sequences.iteritems()):
+      for test_messages in test_messages_sequence:
+        first_request = test_messages.request()
+        second_request = test_messages.request()
+
+        first_response_future = self._invoker.future(group, method)(
+            first_request, test_constants.LONG_TIMEOUT)
+        second_response_future = self._invoker.future(group, method)(
+            second_request, test_constants.LONG_TIMEOUT)
+        first_response = first_response_future.result()
+        second_response = second_response_future.result()
+
+        test_messages.verify(first_request, first_response, self)
+        test_messages.verify(second_request, second_response, self)
+
     for (group, method), test_messages_sequence in (
         self._digest.unary_unary_messages_sequences.iteritems()):
       for test_messages in test_messages_sequence:
@@ -237,26 +256,28 @@
         for request, response in zip(requests, responses):
           test_messages.verify(request, response, self)
 
-  def testParallelInvocations(self):
+  def testWaitingForSomeButNotAllParallelInvocations(self):
+    pool = logging_pool.pool(test_constants.PARALLELISM)
     for (group, method), test_messages_sequence in (
         self._digest.unary_unary_messages_sequences.iteritems()):
       for test_messages in test_messages_sequence:
-        first_request = test_messages.request()
-        second_request = test_messages.request()
+        requests = []
+        response_futures_to_indices = {}
+        for index in range(test_constants.PARALLELISM):
+          request = test_messages.request()
+          inner_response_future = self._invoker.future(group, method)(
+              request, test_constants.LONG_TIMEOUT)
+          outer_response_future = pool.submit(inner_response_future.result)
+          requests.append(request)
+          response_futures_to_indices[outer_response_future] = index
 
-        first_response_future = self._invoker.future(group, method)(
-            first_request, test_constants.LONG_TIMEOUT)
-        second_response_future = self._invoker.future(group, method)(
-            second_request, test_constants.LONG_TIMEOUT)
-        first_response = first_response_future.result()
-        second_response = second_response_future.result()
-
-        test_messages.verify(first_request, first_response, self)
-        test_messages.verify(second_request, second_response, self)
-
-  @unittest.skip('TODO(nathaniel): implement.')
-  def testWaitingForSomeButNotAllParallelInvocations(self):
-    raise NotImplementedError()
+        some_completed_response_futures_iterator = itertools.islice(
+            futures.as_completed(response_futures_to_indices),
+            test_constants.PARALLELISM / 2)
+        for response_future in some_completed_response_futures_iterator:
+          index = response_futures_to_indices[response_future]
+          test_messages.verify(requests[index], response_future.result(), self)
+    pool.shutdown(wait=True)
 
   def testCancelledUnaryRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_receiver.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_receiver.py
index 2e444ff..42a7f4e 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/face/_receiver.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_receiver.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -76,7 +76,7 @@
   def unary_response(self):
     with self._condition:
       if self._abortion is not None:
-        raise AssertionError('Aborted with abortion "%s"!' % self._abortion)
+        raise AssertionError('Aborted: "{}"!'.format(self._abortion))
       elif len(self._responses) != 1:
         raise AssertionError(
             '%d responses received, not exactly one!', len(self._responses))
@@ -88,7 +88,7 @@
       if self._abortion is None:
         return list(self._responses)
       else:
-        raise AssertionError('Aborted with abortion "%s"!' % self._abortion)
+        raise AssertionError('Aborted: "{}"!'.format(self._abortion))
 
   def abortion(self):
     with self._condition:
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index 43adafb..8f33d72 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -525,12 +525,12 @@
   grpc_status_code recv_status;
   char *recv_status_details;
   size_t recv_status_details_capacity;
-  uint write_flag;
+  unsigned write_flag;
 } run_batch_stack;
 
 /* grpc_run_batch_stack_init ensures the run_batch_stack is properly
  * initialized */
-static void grpc_run_batch_stack_init(run_batch_stack *st, uint write_flag) {
+static void grpc_run_batch_stack_init(run_batch_stack *st, unsigned write_flag) {
   MEMZERO(st, run_batch_stack, 1);
   grpc_metadata_array_init(&st->send_metadata);
   grpc_metadata_array_init(&st->send_trailing_metadata);
@@ -696,7 +696,7 @@
   grpc_call_error err;
   VALUE result = Qnil;
   VALUE rb_write_flag = rb_ivar_get(self, id_write_flag);
-  uint write_flag = 0;
+  unsigned write_flag = 0;
   TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
 
   /* Validate the ops args, adding them to a ruby array */
diff --git a/src/ruby/ext/grpc/rb_call_credentials.c b/src/ruby/ext/grpc/rb_call_credentials.c
index 4d719d7..ebcc659 100644
--- a/src/ruby/ext/grpc/rb_call_credentials.c
+++ b/src/ruby/ext/grpc/rb_call_credentials.c
@@ -79,6 +79,7 @@
 static VALUE grpc_rb_call_credentials_callback_rescue(VALUE args,
                                                       VALUE exception_object) {
   VALUE result = rb_hash_new();
+  (void)args;
   rb_hash_aset(result, rb_str_new2("metadata"), Qnil);
   /* Currently only gives the exception class name. It should be possible get
      more details */
@@ -132,6 +133,7 @@
 }
 
 static void grpc_rb_call_credentials_plugin_destroy(void *state) {
+  (void)state;
   // Not sure what needs to be done here
 }
 
diff --git a/src/ruby/ext/grpc/rb_event_thread.c b/src/ruby/ext/grpc/rb_event_thread.c
index 95af091..516f0bd 100644
--- a/src/ruby/ext/grpc/rb_event_thread.c
+++ b/src/ruby/ext/grpc/rb_event_thread.c
@@ -102,6 +102,7 @@
 
 static void *grpc_rb_wait_for_event_no_gil(void *param) {
   grpc_rb_event *event = NULL;
+  (void)param;
   gpr_mu_lock(&event_queue.mu);
   while ((event = grpc_rb_event_queue_dequeue()) == NULL) {
     gpr_cv_wait(&event_queue.cv,
@@ -117,6 +118,7 @@
 }
 
 static void grpc_rb_event_unblocking_func(void *arg) {
+  (void)arg;
   gpr_mu_lock(&event_queue.mu);
   event_queue.abort = true;
   gpr_cv_signal(&event_queue.cv);
@@ -127,6 +129,7 @@
  * events */
 static VALUE grpc_rb_event_thread(VALUE arg) {
   grpc_rb_event *event;
+  (void)arg;
   while(true) {
     event = (grpc_rb_event*)rb_thread_call_without_gvl(
         grpc_rb_wait_for_event_no_gil, NULL,
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 589f724..57a0815 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -130,26 +130,44 @@
 
   prefix ?= /usr/local
 
-  PROTOC = protoc
-  DTRACE = dtrace
+  PROTOC ?= protoc
+  DTRACE ?= dtrace
   CONFIG ?= opt
+  # Doing X ?= Y is the same as:
+  # ifeq ($(origin X), undefined)
+  #  X = Y
+  # endif
+  # but some variables, such as CC, CXX, LD or AR, have defaults.
+  # So instead of using ?= on them, we need to check their origin.
+  # See:
+  #  https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html
+  #  https://www.gnu.org/software/make/manual/html_node/Flavors.html#index-_003f_003d
+  #  https://www.gnu.org/software/make/manual/html_node/Origin-Function.html
+  ifeq ($(origin CC), default)
   CC = $(CC_$(CONFIG))
+  endif
+  ifeq ($(origin CXX), default)
   CXX = $(CXX_$(CONFIG))
+  endif
+  ifeq ($(origin LD), default)
   LD = $(LD_$(CONFIG))
-  LDXX = $(LDXX_$(CONFIG))
+  endif
+  LDXX ?= $(LDXX_$(CONFIG))
+  ifeq ($(origin AR), default)
   AR = ar
+  endif
   ifeq ($(SYSTEM),Linux)
-  STRIP = strip --strip-unneeded
+  STRIP ?= strip --strip-unneeded
   else
   ifeq ($(SYSTEM),Darwin)
-  STRIP = strip -x
+  STRIP ?= strip -x
   else
-  STRIP = strip
+  STRIP ?= strip
   endif
   endif
-  INSTALL = install
-  RM = rm -f
-  PKG_CONFIG = pkg-config
+  INSTALL ?= install
+  RM ?= rm -f
+  PKG_CONFIG ?= pkg-config
 
   ifndef VALID_CONFIG_$(CONFIG)
   $(error Invalid CONFIG value '$(CONFIG)')
@@ -165,15 +183,21 @@
   CXX11_CHECK_CMD = $(CXX) -std=c++11 -o $(TMPOUT) -c test/build/c++11.cc
   HAS_CXX11 = $(shell $(CXX11_CHECK_CMD) 2> /dev/null && echo true || echo false)
 
+  CHECK_NO_SHIFT_NEGATIVE_VALUE_CMD = $(CC) -std=c99 -Werror -Wno-shift-negative-value -o $(TMPOUT) -c test/build/empty.c
+  HAS_NO_SHIFT_NEGATIVE_VALUE = $(shell $(CHECK_NO_SHIFT_NEGATIVE_VALUE_CMD) 2> /dev/null && echo true || echo false)
+  ifeq ($(HAS_NO_SHIFT_NEGATIVE_VALUE),true)
+  W_NO_SHIFT_NEGATIVE_VALUE=-Wno-shift-negative-value
+  endif
+
   # The HOST compiler settings are used to compile the protoc plugins.
   # In most cases, you won't have to change anything, but if you are
   # cross-compiling, you can override these variables from GNU make's
   # command line: make CC=cross-gcc HOST_CC=gcc
 
-  HOST_CC = $(CC)
-  HOST_CXX = $(CXX)
-  HOST_LD = $(LD)
-  HOST_LDXX = $(LDXX)
+  HOST_CC ?= $(CC)
+  HOST_CXX ?= $(CXX)
+  HOST_LD ?= $(LD)
+  HOST_LDXX ?= $(LDXX)
 
   ifdef EXTRA_DEFINES
   DEFINES += $(EXTRA_DEFINES)
@@ -315,14 +339,6 @@
   IS_GIT_FOLDER = true
   endif
 
-  ifeq ($(SYSTEM),Linux)
-  OPENSSL_REQUIRES_DL = true
-  endif
-
-  ifeq ($(SYSTEM),Darwin)
-  OPENSSL_REQUIRES_DL = true
-  endif
-
   ifeq ($(HAS_PKG_CONFIG),true)
   OPENSSL_ALPN_CHECK_CMD = $(PKG_CONFIG) --atleast-version=1.0.2 openssl
   OPENSSL_NPN_CHECK_CMD = $(PKG_CONFIG) --atleast-version=1.0.1 openssl
@@ -341,11 +357,6 @@
   ZLIB_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/zlib.c -lz $(LDFLAGS)
   PROTOBUF_CHECK_CMD = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/protobuf.cc -lprotobuf $(LDFLAGS)
 
-  ifeq ($(OPENSSL_REQUIRES_DL),true)
-  OPENSSL_ALPN_CHECK_CMD += -ldl
-  OPENSSL_NPN_CHECK_CMD += -ldl
-  endif
-
   endif # HAS_PKG_CONFIG
 
   PERFTOOLS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/perftools.c -lprofiler $(LDFLAGS)
@@ -509,9 +520,6 @@
   OPENSSL_MERGE_LIBS += $(LIBDIR)/$(CONFIG)/libboringssl.a
   # need to prefix these to ensure overriding system libraries
   CPPFLAGS := -Ithird_party/boringssl/include $(CPPFLAGS)
-  ifeq ($(OPENSSL_REQUIRES_DL),true)
-  LIBS_SECURE = dl
-  endif # OPENSSL_REQUIRES_DL
   else # EMBED_OPENSSL=false
   ifeq ($(HAS_PKG_CONFIG),true)
   OPENSSL_PKG_CONFIG = true
@@ -531,10 +539,7 @@
   CPPFLAGS += -DTSI_OPENSSL_ALPN_SUPPORT=0
   LIBS_SECURE = $(OPENSSL_LIBS)
   endif # HAS_SYSTEM_OPENSSL_NPN
-  ifeq ($(OPENSSL_REQUIRES_DL),true)
-  LIBS_SECURE += dl
   PC_LIBS_SECURE = $(addprefix -l, $(LIBS_SECURE))
-  endif # OPENSSL_REQUIRES_DL=true
   endif # EMBED_OPENSSL
   endif # NO_SECURE
 
@@ -1438,7 +1443,7 @@
   $(LIB${lib.name.upper()}_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
   $(LIB${lib.name.upper()}_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
   % elif lib.zlib:
-  $(LIB${lib.name.upper()}_OBJS): CFLAGS := $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration -fvisibility=hidden
+  $(LIB${lib.name.upper()}_OBJS): CFLAGS := $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration $(W_NO_SHIFT_NEGATIVE_VALUE) -fvisibility=hidden
   % else:
   % endif
 
diff --git a/templates/binding.gyp.template b/templates/binding.gyp.template
index 8014ff3..71276e7 100644
--- a/templates/binding.gyp.template
+++ b/templates/binding.gyp.template
@@ -7,7 +7,7 @@
   # This file can be regenerated from the template by running
   # tools/buildgen/generate_projects.sh
 
-  # Copyright 2015, Google Inc.
+  # Copyright 2015-2016, Google Inc.
   # All rights reserved.
   #
   # Redistribution and use in source and binary forms, with or without
@@ -56,12 +56,16 @@
       ],
       'include_dirs': [
         '.',
-        'include',
-        '<(node_root_dir)/deps/openssl/openssl/include',
-        '<(node_root_dir)/deps/zlib'
+        'include'
       ],
       'conditions': [
-        ['OS != "win"', {
+        ['OS == "win"', {
+          "include_dirs": [ "third_party/boringssl/include" ]
+        }, {
+          'include_dirs': [
+            '<(node_root_dir)/deps/openssl/openssl/include',
+            '<(node_root_dir)/deps/zlib'
+          ],
           'conditions': [
             ['config=="gcov"', {
               'cflags': [
@@ -74,24 +78,58 @@
                 '-fprofile-arcs'
               ]
             }
-           ]
+           ],
+           ["target_arch=='ia32'", {
+               "include_dirs": [ "<(node_root_dir)/deps/openssl/config/piii" ]
+           }],
+           ["target_arch=='x64'", {
+               "include_dirs": [ "<(node_root_dir)/deps/openssl/config/k8" ]
+           }],
+           ["target_arch=='arm'", {
+               "include_dirs": [ "<(node_root_dir)/deps/openssl/config/arm" ]
+           }]
           ]
-        }],
-        ["target_arch=='ia32'", {
-            "include_dirs": [ "<(node_root_dir)/deps/openssl/config/piii" ]
-        }],
-        ["target_arch=='x64'", {
-            "include_dirs": [ "<(node_root_dir)/deps/openssl/config/k8" ]
-        }],
-        ["target_arch=='arm'", {
-            "include_dirs": [ "<(node_root_dir)/deps/openssl/config/arm" ]
         }]
       ]
     },
+    'conditions': [
+      ['OS == "win"', {
+        'targets': [
+          # Only want to compile BoringSSL and zlib under Windows
+          % for module in node_modules:
+          % for lib in libs:
+          % if lib.name in module.transitive_deps and lib.name in ('boringssl', 'z'):
+          {
+            'cflags': [
+              '-std=c99',
+              '-Wall',
+              '-Werror'
+            ],
+            'target_name': '${lib.name}',
+            'product_prefix': 'lib',
+            'type': 'static_library',
+            'dependencies': [
+              % for dep in getattr(lib, 'deps', []):
+              '${dep}',
+              % endfor
+            ],
+            'sources': [
+              % for source in lib.src:
+              '${source}',
+              % endfor
+            ],
+            "include_dirs": [ "third_party/boringssl/include" ]
+          },
+          % endif
+          % endfor
+          % endfor
+        ]
+      }]
+    ],
     'targets': [
       % for module in node_modules:
       % for lib in libs:
-      % if lib.name in module.transitive_deps:
+      % if lib.name in module.transitive_deps and lib.name not in ('boringssl', 'z'):
       {
         'cflags': [
           '-std=c99',
@@ -117,7 +155,7 @@
               'MACOSX_DEPLOYMENT_TARGET': '10.9'
             }
           }]
-        ],
+        ]
       },
       % endif
       % endfor
@@ -138,13 +176,22 @@
           '-g'
         ],
         "conditions": [
-          ['OS == "mac"', {
+          ['OS=="mac"', {
             'xcode_settings': {
               'MACOSX_DEPLOYMENT_TARGET': '10.9',
               'OTHER_CFLAGS': [
                 '-stdlib=libc++'
               ]
             }
+          }],
+          ['OS=="win"', {
+            'dependencies': [
+              % for dep in getattr(module, 'deps', []):
+              % if dep in ('boringssl', 'z'):
+              "${dep}",
+              % endif
+              % endfor
+            ]
           }]
         ],
         "target_name": "${module.name}",
@@ -155,10 +202,23 @@
         ],
         "dependencies": [
           % for dep in getattr(module, 'deps', []):
+          % if dep not in ('boringssl', 'z'):
           "${dep}",
+          % endif
           % endfor
         ]
       },
       % endfor
+      {
+        "target_name": "action_after_build",
+        "type": "none",
+        "dependencies": [ "<(module_name)" ],
+        "copies": [
+          {
+            "files": [ "<(PRODUCT_DIR)/<(module_name).node"],
+            "destination": "<(module_path)"
+          }
+        ]
+      }
     ]
   }
diff --git a/templates/package.json.template b/templates/package.json.template
index ec6827e..ed4dca5 100644
--- a/templates/package.json.template
+++ b/templates/package.json.template
@@ -24,12 +24,14 @@
       "lint": "node ./node_modules/jshint/bin/jshint src/node/src src/node/test src/node/interop src/node/index.js",
       "test": "./node_modules/.bin/mocha src/node/test && npm run-script lint",
       "gen_docs": "./node_modules/.bin/jsdoc -c src/node/jsdoc_conf.json",
-      "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha src/node/test"
+      "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha src/node/test",
+      "preinstall": "npm install node-pre-gyp",
+      "install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build"
     },
     "dependencies": {
-      "bindings": "^1.2.0",
       "lodash": "^3.9.3",
       "nan": "^2.0.0",
+      "node-pre-gyp": "^0.6.19",
       "protobufjs": "^4.0.0"
     },
     "devDependencies": {
@@ -47,6 +49,14 @@
     "engines": {
       "node": ">=0.10.13"
     },
+    "binary": {
+      "module_name": "grpc_node",
+      "module_path": "./build/Release/",
+      "host": "https://storage.googleapis.com/",
+      "remote_path": "grpc-precompiled-binaries/node/{name}/v{version}",
+      "package_name": "{node_abi}-{platform}-{arch}.tar.gz",
+      "module_path": "src/node/extension_binary"
+    },
     "files": [
       "LICENSE",
       "src/node/README.md",
diff --git a/test/core/support/alloc_test.c b/test/core/support/alloc_test.c
index a7051a4..6bdba8c 100644
--- a/test/core/support/alloc_test.c
+++ b/test/core/support/alloc_test.c
@@ -39,7 +39,9 @@
 
 static void *fake_realloc(void *addr, size_t size) { return (void *)size; }
 
-static void fake_free(void *addr) { *((intptr_t *)addr) = 0xdeadd00d; }
+static void fake_free(void *addr) {
+  *((intptr_t *)addr) = (intptr_t)0xdeadd00d;
+}
 
 static void test_custom_allocs() {
   const gpr_allocation_functions default_fns = gpr_get_allocation_functions();
@@ -52,7 +54,7 @@
   GPR_ASSERT((void *)(size_t)0xcafed00d == gpr_realloc(0, 0xcafed00d));
 
   gpr_free(&addr_to_free);
-  GPR_ASSERT(addr_to_free == 0xdeadd00d);
+  GPR_ASSERT(addr_to_free == (intptr_t)0xdeadd00d);
 
   /* Restore and check we don't get funky values and that we don't leak */
   gpr_set_allocation_functions(default_fns);
diff --git a/test/core/transport/chttp2/hpack_table_test.c b/test/core/transport/chttp2/hpack_table_test.c
index 39f4174..3c5f2e4 100644
--- a/test/core/transport/chttp2/hpack_table_test.c
+++ b/test/core/transport/chttp2/hpack_table_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -236,7 +236,7 @@
 
   /* overflow the string buffer, check find still works */
   for (i = 0; i < 10000; i++) {
-    gpr_ltoa(i, buffer);
+    int64_ttoa(i, buffer);
     elem = grpc_mdelem_from_strings("test", buffer);
     GPR_ASSERT(grpc_chttp2_hptbl_add(&tbl, elem));
     GRPC_MDELEM_UNREF(elem);
@@ -256,7 +256,7 @@
 
   for (i = 0; i < tbl.num_ents; i++) {
     uint32_t expect = 9999 - i;
-    gpr_ltoa(expect, buffer);
+    int64_ttoa(expect, buffer);
 
     r = find_simple(&tbl, "test", buffer);
     GPR_ASSERT(r.index == i + 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY);
diff --git a/test/core/util/port_posix.c b/test/core/util/port_posix.c
index 732a51c..11cefbf 100644
--- a/test/core/util/port_posix.c
+++ b/test/core/util/port_posix.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,6 +37,7 @@
 
 #include "test/core/util/port.h"
 
+#include <math.h>
 #include <netinet/in.h>
 #include <sys/socket.h>
 #include <stdio.h>
@@ -229,10 +230,10 @@
     grpc_httpcli_request req;
     memset(&req, 0, sizeof(req));
     GPR_ASSERT(pr->retries < 10);
+    sleep(1 + (unsigned)(pow(1.3, pr->retries) * rand() / RAND_MAX));
     pr->retries++;
     req.host = pr->server;
     req.path = "/get";
-    sleep(1);
     grpc_httpcli_get(exec_ctx, pr->ctx, &pr->pollset, &req,
                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), got_port_from_server,
                      pr);
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index f8027bc..5a414eb 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -244,7 +244,8 @@
           gpr_time_from_micros(request->param().server_cancel_after_us(),
                                GPR_TIMESPAN)));
       return Status::CANCELLED;
-    } else {
+    } else if (!request->has_param() ||
+               !request->param().skip_cancelled_check()) {
       EXPECT_FALSE(context->IsCancelled());
     }
 
@@ -823,6 +824,7 @@
   EchoRequest request;
   EchoResponse response;
   request.set_message("Hello");
+  request.mutable_param()->set_skip_cancelled_check(true);
 
   ClientContext context;
   std::chrono::system_clock::time_point deadline =
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index f270cd0..e423ee2 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -46,13 +46,14 @@
 #include <grpc++/client_context.h>
 #include <grpc++/generic/generic_stub.h>
 #include <grpc/grpc.h>
+#include <grpc/support/cpu.h>
 #include <grpc/support/histogram.h>
 #include <grpc/support/log.h>
 
+#include "src/proto/grpc/testing/services.grpc.pb.h"
 #include "test/cpp/qps/client.h"
 #include "test/cpp/qps/timer.h"
 #include "test/cpp/util/create_test_channel.h"
-#include "src/proto/grpc/testing/services.grpc.pb.h"
 
 namespace grpc {
 namespace testing {
@@ -164,14 +165,15 @@
               std::function<std::unique_ptr<StubType>(std::shared_ptr<Channel>)>
                   create_stub)
       : ClientImpl<StubType, RequestType>(config, create_stub),
+        num_async_threads_(NumThreads(config)),
         channel_lock_(new std::mutex[config.client_channels()]),
         contexts_(config.client_channels()),
         max_outstanding_per_channel_(config.outstanding_rpcs_per_channel()),
         channel_count_(config.client_channels()),
-        pref_channel_inc_(config.async_client_threads()) {
-    SetupLoadTest(config, config.async_client_threads());
+        pref_channel_inc_(num_async_threads_) {
+    SetupLoadTest(config, num_async_threads_);
 
-    for (int i = 0; i < config.async_client_threads(); i++) {
+    for (int i = 0; i < num_async_threads_; i++) {
       cli_cqs_.emplace_back(new CompletionQueue);
       if (!closed_loop_) {
         rpc_deadlines_.emplace_back();
@@ -324,6 +326,9 @@
     return true;
   }
 
+ protected:
+  int num_async_threads_;
+
  private:
   class boolean {  // exists only to avoid data-race on vector<bool>
    public:
@@ -338,6 +343,15 @@
    private:
     bool val_;
   };
+  static int NumThreads(const ClientConfig& config) {
+    int num_threads = config.async_client_threads();
+    if (num_threads <= 0) {  // Use dynamic sizing
+      num_threads = gpr_cpu_num_cores();
+      gpr_log(GPR_INFO, "Sizing client server to %d threads", num_threads);
+    }
+    return num_threads;
+  }
+
   std::vector<std::unique_ptr<CompletionQueue>> cli_cqs_;
 
   std::vector<deadline_list> rpc_deadlines_;  // per thread deadlines
@@ -363,7 +377,7 @@
  public:
   explicit AsyncUnaryClient(const ClientConfig& config)
       : AsyncClient(config, SetupCtx, BenchmarkStubCreator) {
-    StartThreads(config.async_client_threads());
+    StartThreads(num_async_threads_);
   }
   ~AsyncUnaryClient() GRPC_OVERRIDE { EndThreads(); }
 
@@ -461,7 +475,7 @@
     // async streaming currently only supports closed loop
     GPR_ASSERT(closed_loop_);
 
-    StartThreads(config.async_client_threads());
+    StartThreads(num_async_threads_);
   }
 
   ~AsyncStreamingClient() GRPC_OVERRIDE { EndThreads(); }
@@ -566,7 +580,7 @@
     // async streaming currently only supports closed loop
     GPR_ASSERT(closed_loop_);
 
-    StartThreads(config.async_client_threads());
+    StartThreads(num_async_threads_);
   }
 
   ~GenericAsyncStreamingClient() GRPC_OVERRIDE { EndThreads(); }
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index acb265b..4914e19 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,24 +31,24 @@
  *
  */
 
+#include <deque>
 #include <list>
 #include <thread>
-#include <deque>
 #include <vector>
 
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/host_port.h>
 #include <grpc++/client_context.h>
 #include <grpc++/create_channel.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
 
 #include "src/core/support/env.h"
+#include "src/proto/grpc/testing/services.grpc.pb.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 #include "test/cpp/qps/driver.h"
 #include "test/cpp/qps/histogram.h"
 #include "test/cpp/qps/qps_worker.h"
-#include "src/proto/grpc/testing/services.grpc.pb.h"
 
 using std::list;
 using std::thread;
@@ -142,6 +142,12 @@
     }
   }
 
+  // if num_clients is set to <=0, do dynamic sizing: all workers
+  // except for servers are clients
+  if (num_clients <= 0) {
+    num_clients = workers.size() - num_servers;
+  }
+
   // TODO(ctiller): support running multiple configurations, and binpack
   // client/server pairs
   // to available workers
@@ -161,6 +167,8 @@
   // where class contained in std::vector must have a copy constructor
   auto* servers = new ServerData[num_servers];
   for (size_t i = 0; i < num_servers; i++) {
+    gpr_log(GPR_INFO, "Starting server on %s (worker #%d)", workers[i].c_str(),
+            i);
     servers[i].stub = WorkerService::NewStub(
         CreateChannel(workers[i], InsecureChannelCredentials()));
     ServerArgs args;
@@ -188,6 +196,8 @@
   // where class contained in std::vector must have a copy constructor
   auto* clients = new ClientData[num_clients];
   for (size_t i = 0; i < num_clients; i++) {
+    gpr_log(GPR_INFO, "Starting client on %s (worker #%d)",
+            workers[i + num_servers].c_str(), i + num_servers);
     clients[i].stub = WorkerService::NewStub(
         CreateChannel(workers[i + num_servers], InsecureChannelCredentials()));
     ClientArgs args;
diff --git a/test/cpp/qps/generic_async_streaming_ping_pong_test.cc b/test/cpp/qps/generic_async_streaming_ping_pong_test.cc
index 2b2e1c8..81c0f24 100644
--- a/test/cpp/qps/generic_async_streaming_ping_pong_test.cc
+++ b/test/cpp/qps/generic_async_streaming_ping_pong_test.cc
@@ -60,7 +60,7 @@
   bbuf->set_req_size(0);
 
   ServerConfig server_config;
-  server_config.set_server_type(ASYNC_SERVER);
+  server_config.set_server_type(ASYNC_GENERIC_SERVER);
   server_config.set_host("localhost");
   server_config.set_async_server_threads(1);
 
diff --git a/test/cpp/qps/qps_driver.cc b/test/cpp/qps/qps_driver.cc
index 9816a09..680e4b1 100644
--- a/test/cpp/qps/qps_driver.cc
+++ b/test/cpp/qps/qps_driver.cc
@@ -153,7 +153,7 @@
 
   ServerConfig server_config;
   server_config.set_server_type(server_type);
-  server_config.set_host("localhost");
+  server_config.set_host("::");  // Use the wildcard server address
   server_config.set_async_server_threads(FLAGS_async_server_threads);
 
   if (FLAGS_secure_test) {
@@ -170,7 +170,7 @@
   GPR_ASSERT(!client_config.payload_config().has_bytebuf_params() ||
              (client_config.client_type() == ASYNC_CLIENT &&
               client_config.rpc_type() == STREAMING &&
-              server_config.server_type() == ASYNC_SERVER));
+              server_config.server_type() == ASYNC_GENERIC_SERVER));
 
   const auto result = RunScenario(
       client_config, FLAGS_num_clients, server_config, FLAGS_num_servers,
diff --git a/test/cpp/qps/qps_worker.cc b/test/cpp/qps/qps_worker.cc
index c0276d0..6316605 100644
--- a/test/cpp/qps/qps_worker.cc
+++ b/test/cpp/qps/qps_worker.cc
@@ -61,6 +61,11 @@
 namespace testing {
 
 static std::unique_ptr<Client> CreateClient(const ClientConfig& config) {
+  gpr_log(GPR_INFO, "Starting client of type %s %s %d",
+          ClientType_Name(config.client_type()).c_str(),
+          RpcType_Name(config.rpc_type()).c_str(),
+          config.payload_config().has_bytebuf_params());
+
   switch (config.client_type()) {
     case ClientType::SYNC_CLIENT:
       return (config.rpc_type() == RpcType::UNARY)
@@ -81,6 +86,9 @@
 static void LimitCores(int cores) {}
 
 static std::unique_ptr<Server> CreateServer(const ServerConfig& config) {
+  gpr_log(GPR_INFO, "Starting server of type %s",
+          ServerType_Name(config.server_type()).c_str());
+
   if (config.core_limit() > 0) {
     LimitCores(config.core_limit());
   }
@@ -89,6 +97,8 @@
       return CreateSynchronousServer(config);
     case ServerType::ASYNC_SERVER:
       return CreateAsyncServer(config);
+    case ServerType::ASYNC_GENERIC_SERVER:
+      return CreateAsyncGenericServer(config);
     default:
       abort();
   }
@@ -169,22 +179,29 @@
     if (!args.has_setup()) {
       return Status(StatusCode::INVALID_ARGUMENT, "");
     }
+    gpr_log(GPR_INFO, "RunClientBody: about to create client");
     auto client = CreateClient(args.setup());
     if (!client) {
       return Status(StatusCode::INVALID_ARGUMENT, "");
     }
+    gpr_log(GPR_INFO, "RunClientBody: client created");
     ClientStatus status;
     if (!stream->Write(status)) {
       return Status(StatusCode::UNKNOWN, "");
     }
+    gpr_log(GPR_INFO, "RunClientBody: creation status reported");
     while (stream->Read(&args)) {
+      gpr_log(GPR_INFO, "RunClientBody: Message read");
       if (!args.has_mark()) {
+        gpr_log(GPR_INFO, "RunClientBody: Message is not a mark!");
         return Status(StatusCode::INVALID_ARGUMENT, "");
       }
       *status.mutable_stats() = client->Mark(args.mark().reset());
       stream->Write(status);
+      gpr_log(GPR_INFO, "RunClientBody: Mark response given");
     }
 
+    gpr_log(GPR_INFO, "RunClientBody: Returning");
     return Status::OK;
   }
 
@@ -200,24 +217,31 @@
     if (server_port_ != 0) {
       args.mutable_setup()->set_port(server_port_);
     }
+    gpr_log(GPR_INFO, "RunServerBody: about to create server");
     auto server = CreateServer(args.setup());
     if (!server) {
       return Status(StatusCode::INVALID_ARGUMENT, "");
     }
+    gpr_log(GPR_INFO, "RunServerBody: server created");
     ServerStatus status;
     status.set_port(server->port());
     status.set_cores(server->cores());
     if (!stream->Write(status)) {
       return Status(StatusCode::UNKNOWN, "");
     }
+    gpr_log(GPR_INFO, "RunServerBody: creation status reported");
     while (stream->Read(&args)) {
+      gpr_log(GPR_INFO, "RunServerBody: Message read");
       if (!args.has_mark()) {
+        gpr_log(GPR_INFO, "RunServerBody: Message not a mark!");
         return Status(StatusCode::INVALID_ARGUMENT, "");
       }
       *status.mutable_stats() = server->Mark(args.mark().reset());
       stream->Write(status);
+      gpr_log(GPR_INFO, "RunServerBody: Mark response given");
     }
 
+    gpr_log(GPR_INFO, "RunServerBody: Returning");
     return Status::OK;
   }
 
diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h
index 32a3e85..196fdac 100644
--- a/test/cpp/qps/server.h
+++ b/test/cpp/qps/server.h
@@ -108,6 +108,7 @@
 
 std::unique_ptr<Server> CreateSynchronousServer(const ServerConfig& config);
 std::unique_ptr<Server> CreateAsyncServer(const ServerConfig& config);
+std::unique_ptr<Server> CreateAsyncGenericServer(const ServerConfig& config);
 
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index d530dac..ffa6226 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -50,8 +50,8 @@
 #include <grpc/support/log.h>
 #include <gtest/gtest.h>
 
-#include "test/cpp/qps/server.h"
 #include "src/proto/grpc/testing/services.grpc.pb.h"
+#include "test/cpp/qps/server.h"
 
 namespace grpc {
 namespace testing {
@@ -85,7 +85,13 @@
 
     register_service(&builder, &async_service_);
 
-    for (int i = 0; i < config.async_server_threads(); i++) {
+    int num_threads = config.async_server_threads();
+    if (num_threads <= 0) {  // dynamic sizing
+      num_threads = cores();
+      gpr_log(GPR_INFO, "Sizing async server to %d threads", num_threads);
+    }
+
+    for (int i = 0; i < num_threads; i++) {
       srv_cqs_.emplace_back(builder.AddCompletionQueue());
     }
 
@@ -96,8 +102,8 @@
     auto process_rpc_bound =
         std::bind(process_rpc, config.payload_config(), _1, _2);
 
-    for (int i = 0; i < 10000 / config.async_server_threads(); i++) {
-      for (int j = 0; j < config.async_server_threads(); j++) {
+    for (int i = 0; i < 10000 / num_threads; i++) {
+      for (int j = 0; j < num_threads; j++) {
         if (request_unary_function) {
           auto request_unary =
               std::bind(request_unary_function, &async_service_, _1, _2, _3,
@@ -115,10 +121,10 @@
       }
     }
 
-    for (int i = 0; i < config.async_server_threads(); i++) {
+    for (int i = 0; i < num_threads; i++) {
       shutdown_state_.emplace_back(new PerThreadShutdownState());
     }
-    for (int i = 0; i < config.async_server_threads(); i++) {
+    for (int i = 0; i < num_threads; i++) {
       threads_.emplace_back(&AsyncQpsServerTest::ThreadFunc, this, i);
     }
   }
@@ -373,7 +379,7 @@
                                 const ByteBuffer *request,
                                 ByteBuffer *response) {
   int resp_size = payload_config.bytebuf_params().resp_size();
-  std::unique_ptr<char> buf(new char[resp_size]);
+  std::unique_ptr<char[]> buf(new char[resp_size]);
   gpr_slice s = gpr_slice_from_copied_buffer(buf.get(), resp_size);
   Slice slice(s, Slice::STEAL_REF);
   *response = ByteBuffer(&slice, 1);
diff --git a/tools/buildgen/generate_projects.py b/tools/buildgen/generate_projects.py
index 083a978..965dd29 100755
--- a/tools/buildgen/generate_projects.py
+++ b/tools/buildgen/generate_projects.py
@@ -47,6 +47,7 @@
 argp = argparse.ArgumentParser()
 argp.add_argument('json', nargs='+')
 argp.add_argument('--templates', nargs='+', default=[])
+argp.add_argument('--jobs', '-j', default=multiprocessing.cpu_count(), type=int)
 args = argp.parse_args()
 
 json = args.json
@@ -87,7 +88,7 @@
     cmd.append(root + '/' + f)
     jobs.append(jobset.JobSpec(cmd, shortname=out, timeout_seconds=None))
 
-jobset.run(jobs, maxjobs=multiprocessing.cpu_count())
+jobset.run(jobs, maxjobs=args.jobs)
 
 if test is not None:
   for s, g in test.iteritems():
diff --git a/tools/jenkins/grpc_artifact_linux_x64/Dockerfile b/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile
similarity index 100%
rename from tools/jenkins/grpc_artifact_linux_x64/Dockerfile
rename to tools/dockerfile/grpc_artifact_linux_x64/Dockerfile
diff --git a/tools/jenkins/grpc_artifact_linux_x86/Dockerfile b/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile
similarity index 100%
rename from tools/jenkins/grpc_artifact_linux_x86/Dockerfile
rename to tools/dockerfile/grpc_artifact_linux_x86/Dockerfile
diff --git a/tools/jenkins/grpc_interop_csharp/Dockerfile b/tools/dockerfile/grpc_interop_csharp/Dockerfile
similarity index 98%
rename from tools/jenkins/grpc_interop_csharp/Dockerfile
rename to tools/dockerfile/grpc_interop_csharp/Dockerfile
index 3789cd3..c3c7948 100644
--- a/tools/jenkins/grpc_interop_csharp/Dockerfile
+++ b/tools/dockerfile/grpc_interop_csharp/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_csharp/build_interop.sh b/tools/dockerfile/grpc_interop_csharp/build_interop.sh
similarity index 100%
rename from tools/jenkins/grpc_interop_csharp/build_interop.sh
rename to tools/dockerfile/grpc_interop_csharp/build_interop.sh
diff --git a/tools/jenkins/grpc_interop_stress_cxx/Dockerfile b/tools/dockerfile/grpc_interop_cxx/Dockerfile
similarity index 100%
copy from tools/jenkins/grpc_interop_stress_cxx/Dockerfile
copy to tools/dockerfile/grpc_interop_cxx/Dockerfile
diff --git a/tools/jenkins/grpc_interop_cxx/build_interop.sh b/tools/dockerfile/grpc_interop_cxx/build_interop.sh
similarity index 97%
rename from tools/jenkins/grpc_interop_cxx/build_interop.sh
rename to tools/dockerfile/grpc_interop_cxx/build_interop.sh
index 1c0828d..903c31b 100755
--- a/tools/jenkins/grpc_interop_cxx/build_interop.sh
+++ b/tools/dockerfile/grpc_interop_cxx/build_interop.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_go/Dockerfile b/tools/dockerfile/grpc_interop_go/Dockerfile
similarity index 97%
rename from tools/jenkins/grpc_interop_go/Dockerfile
rename to tools/dockerfile/grpc_interop_go/Dockerfile
index bb60f09..f83e18c 100644
--- a/tools/jenkins/grpc_interop_go/Dockerfile
+++ b/tools/dockerfile/grpc_interop_go/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_go/build_interop.sh b/tools/dockerfile/grpc_interop_go/build_interop.sh
similarity index 98%
rename from tools/jenkins/grpc_interop_go/build_interop.sh
rename to tools/dockerfile/grpc_interop_go/build_interop.sh
index e891549..224b004 100755
--- a/tools/jenkins/grpc_interop_go/build_interop.sh
+++ b/tools/dockerfile/grpc_interop_go/build_interop.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_go/Dockerfile b/tools/dockerfile/grpc_interop_http2/Dockerfile
similarity index 97%
copy from tools/jenkins/grpc_interop_go/Dockerfile
copy to tools/dockerfile/grpc_interop_http2/Dockerfile
index bb60f09..f83e18c 100644
--- a/tools/jenkins/grpc_interop_go/Dockerfile
+++ b/tools/dockerfile/grpc_interop_http2/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_http2/build_interop.sh b/tools/dockerfile/grpc_interop_http2/build_interop.sh
similarity index 97%
rename from tools/jenkins/grpc_interop_http2/build_interop.sh
rename to tools/dockerfile/grpc_interop_http2/build_interop.sh
index 46ddaf9..5f701e3 100755
--- a/tools/jenkins/grpc_interop_http2/build_interop.sh
+++ b/tools/dockerfile/grpc_interop_http2/build_interop.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_java/Dockerfile b/tools/dockerfile/grpc_interop_java/Dockerfile
similarity index 98%
rename from tools/jenkins/grpc_interop_java/Dockerfile
rename to tools/dockerfile/grpc_interop_java/Dockerfile
index 1ec24a9..5ba5324 100644
--- a/tools/jenkins/grpc_interop_java/Dockerfile
+++ b/tools/dockerfile/grpc_interop_java/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_java/build_interop.sh b/tools/dockerfile/grpc_interop_java/build_interop.sh
similarity index 97%
rename from tools/jenkins/grpc_interop_java/build_interop.sh
rename to tools/dockerfile/grpc_interop_java/build_interop.sh
index 9997c63..9c9591a 100755
--- a/tools/jenkins/grpc_interop_java/build_interop.sh
+++ b/tools/dockerfile/grpc_interop_java/build_interop.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_node/Dockerfile b/tools/dockerfile/grpc_interop_node/Dockerfile
similarity index 98%
rename from tools/jenkins/grpc_interop_node/Dockerfile
rename to tools/dockerfile/grpc_interop_node/Dockerfile
index db5aff8..3f0f918 100644
--- a/tools/jenkins/grpc_interop_node/Dockerfile
+++ b/tools/dockerfile/grpc_interop_node/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_node/build_interop.sh b/tools/dockerfile/grpc_interop_node/build_interop.sh
similarity index 95%
rename from tools/jenkins/grpc_interop_node/build_interop.sh
rename to tools/dockerfile/grpc_interop_node/build_interop.sh
index 3b69715..526dd61 100755
--- a/tools/jenkins/grpc_interop_node/build_interop.sh
+++ b/tools/dockerfile/grpc_interop_node/build_interop.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -45,4 +45,4 @@
 
 # build Node interop client & server
 npm install -g node-gyp
-(npm install && node-gyp rebuild)
+npm install --unsafe-perm --build-from-source
diff --git a/tools/jenkins/grpc_interop_php/Dockerfile b/tools/dockerfile/grpc_interop_php/Dockerfile
similarity index 98%
rename from tools/jenkins/grpc_interop_php/Dockerfile
rename to tools/dockerfile/grpc_interop_php/Dockerfile
index cf3e791..4f5b3fc 100644
--- a/tools/jenkins/grpc_interop_php/Dockerfile
+++ b/tools/dockerfile/grpc_interop_php/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_php/build_interop.sh b/tools/dockerfile/grpc_interop_php/build_interop.sh
similarity index 98%
rename from tools/jenkins/grpc_interop_php/build_interop.sh
rename to tools/dockerfile/grpc_interop_php/build_interop.sh
index 87262f1..2bffbd8 100755
--- a/tools/jenkins/grpc_interop_php/build_interop.sh
+++ b/tools/dockerfile/grpc_interop_php/build_interop.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_python/Dockerfile b/tools/dockerfile/grpc_interop_python/Dockerfile
similarity index 98%
rename from tools/jenkins/grpc_interop_python/Dockerfile
rename to tools/dockerfile/grpc_interop_python/Dockerfile
index 047604b..ef4432d 100644
--- a/tools/jenkins/grpc_interop_python/Dockerfile
+++ b/tools/dockerfile/grpc_interop_python/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_python/build_interop.sh b/tools/dockerfile/grpc_interop_python/build_interop.sh
similarity index 97%
rename from tools/jenkins/grpc_interop_python/build_interop.sh
rename to tools/dockerfile/grpc_interop_python/build_interop.sh
index 39c9367..203b012 100755
--- a/tools/jenkins/grpc_interop_python/build_interop.sh
+++ b/tools/dockerfile/grpc_interop_python/build_interop.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_ruby/Dockerfile b/tools/dockerfile/grpc_interop_ruby/Dockerfile
similarity index 98%
rename from tools/jenkins/grpc_interop_ruby/Dockerfile
rename to tools/dockerfile/grpc_interop_ruby/Dockerfile
index ff201fa..b3383af 100644
--- a/tools/jenkins/grpc_interop_ruby/Dockerfile
+++ b/tools/dockerfile/grpc_interop_ruby/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_ruby/build_interop.sh b/tools/dockerfile/grpc_interop_ruby/build_interop.sh
similarity index 97%
rename from tools/jenkins/grpc_interop_ruby/build_interop.sh
rename to tools/dockerfile/grpc_interop_ruby/build_interop.sh
index c5023f5..04288bf 100755
--- a/tools/jenkins/grpc_interop_ruby/build_interop.sh
+++ b/tools/dockerfile/grpc_interop_ruby/build_interop.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_stress_cxx/Dockerfile b/tools/dockerfile/grpc_interop_stress_cxx/Dockerfile
similarity index 100%
rename from tools/jenkins/grpc_interop_stress_cxx/Dockerfile
rename to tools/dockerfile/grpc_interop_stress_cxx/Dockerfile
diff --git a/tools/jenkins/grpc_interop_stress_cxx/build_interop_stress.sh b/tools/dockerfile/grpc_interop_stress_cxx/build_interop_stress.sh
similarity index 100%
rename from tools/jenkins/grpc_interop_stress_cxx/build_interop_stress.sh
rename to tools/dockerfile/grpc_interop_stress_cxx/build_interop_stress.sh
diff --git a/tools/jenkins/grpc_linuxbrew/Dockerfile b/tools/dockerfile/grpc_linuxbrew/Dockerfile
similarity index 98%
rename from tools/jenkins/grpc_linuxbrew/Dockerfile
rename to tools/dockerfile/grpc_linuxbrew/Dockerfile
index 848489e..8c179da 100644
--- a/tools/jenkins/grpc_linuxbrew/Dockerfile
+++ b/tools/dockerfile/grpc_linuxbrew/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/jenkins/grpc_interop_cxx/Dockerfile b/tools/dockerfile/grpc_sanity/Dockerfile
similarity index 78%
rename from tools/jenkins/grpc_interop_cxx/Dockerfile
rename to tools/dockerfile/grpc_sanity/Dockerfile
index 1fa1907..6f7797d 100644
--- a/tools/jenkins/grpc_interop_cxx/Dockerfile
+++ b/tools/dockerfile/grpc_sanity/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -27,12 +27,11 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
+# Dockerfile for running gRPC sanity tests
 
 FROM debian:jessie
 
-# Install Git.
+# Install Git and basic packages.
 RUN apt-get update && apt-get install -y \
   autoconf \
   autotools-dev \
@@ -43,13 +42,16 @@
   gcc \
   gcc-multilib \
   git \
+  golang \
   gyp \
+  lcov \
   libc6 \
   libc6-dbg \
   libc6-dev \
   libgtest-dev \
   libtool \
   make \
+  perl \
   strace \
   python-dev \
   python-setuptools \
@@ -59,17 +61,19 @@
   wget \
   zip && apt-get clean
 
-# Prepare ccache
-RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
-RUN ln -s /usr/bin/ccache /usr/local/bin/g++
-RUN ln -s /usr/bin/ccache /usr/local/bin/cc
-RUN ln -s /usr/bin/ccache /usr/local/bin/c++
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+##################
+# Sanity test dependencies
+RUN apt-get update && apt-get install -y python-pip
+RUN pip install simplejson mako
 
 ##################
-# C++ dependencies
-RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang
+# Docker "inception".
+# Note this is quite the ugly hack.
+# This makes sure that the docker binary we inject has its dependencies.
+RUN curl https://get.docker.com/ | sh
+RUN apt-get remove --purge -y docker-engine
+
+RUN mkdir /var/local/jenkins
 
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/jenkins/grpc_jenkins_slave_32bits/Dockerfile b/tools/dockerfile/grpc_tests_multilang_x64/Dockerfile
similarity index 93%
copy from tools/jenkins/grpc_jenkins_slave_32bits/Dockerfile
copy to tools/dockerfile/grpc_tests_multilang_x64/Dockerfile
index 2323f23..7785f3d 100644
--- a/tools/jenkins/grpc_jenkins_slave_32bits/Dockerfile
+++ b/tools/dockerfile/grpc_tests_multilang_x64/Dockerfile
@@ -27,10 +27,9 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
+# Dockerfile for running gRPC test suites inside a docker container.
 
-FROM 32bit/debian:jessie
+FROM debian:jessie
 
 # Install Git and basic packages.
 RUN apt-get update && apt-get install -y \
@@ -95,8 +94,6 @@
 RUN cd /var/local && wget www.nuget.org/NuGet.exe
 ENV NUGET mono /var/local/NuGet.exe
 
-# TODO(jtattermusch): add dependencies for other languages
-
 ##################
 # Node dependencies
 
@@ -128,11 +125,12 @@
 RUN apt-get update && apt-get install -y \
     python-all-dev \
     python3-all-dev \
-    python-pip \
-    python-virtualenv
+    python-pip
 
 # Install Python packages from PyPI
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 tox
 
 # For sanity test
 RUN pip install simplejson mako
@@ -153,12 +151,8 @@
 
 ##################
 # Zookeeper dependencies
-
-# Install dependencies
-
 RUN apt-get install -y libzookeeper-mt-dev
 
-
 RUN mkdir /var/local/jenkins
 
 # Define the default command.
diff --git a/tools/jenkins/grpc_jenkins_slave_32bits/Dockerfile b/tools/dockerfile/grpc_tests_multilang_x86/Dockerfile
similarity index 96%
rename from tools/jenkins/grpc_jenkins_slave_32bits/Dockerfile
rename to tools/dockerfile/grpc_tests_multilang_x86/Dockerfile
index 2323f23..c5cd45e 100644
--- a/tools/jenkins/grpc_jenkins_slave_32bits/Dockerfile
+++ b/tools/dockerfile/grpc_tests_multilang_x86/Dockerfile
@@ -27,8 +27,7 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
+# Dockerfile for running gRPC test suites inside a docker container.
 
 FROM 32bit/debian:jessie
 
@@ -95,8 +94,6 @@
 RUN cd /var/local && wget www.nuget.org/NuGet.exe
 ENV NUGET mono /var/local/NuGet.exe
 
-# TODO(jtattermusch): add dependencies for other languages
-
 ##################
 # Node dependencies
 
@@ -153,9 +150,6 @@
 
 ##################
 # Zookeeper dependencies
-
-# Install dependencies
-
 RUN apt-get install -y libzookeeper-mt-dev
 
 
diff --git a/tools/jenkins/build_docker_and_run_tests.sh b/tools/jenkins/build_docker_and_run_tests.sh
index 562cfcb..58163bb 100755
--- a/tools/jenkins/build_docker_and_run_tests.sh
+++ b/tools/jenkins/build_docker_and_run_tests.sh
@@ -47,11 +47,15 @@
 # Create a local branch so the child Docker script won't complain
 git branch -f jenkins-docker
 
-# Use image name based on Dockerfile checksum
-DOCKER_IMAGE_NAME=grpc_jenkins_slave${docker_suffix}_`sha1sum tools/jenkins/grpc_jenkins_slave/Dockerfile | cut -f1 -d\ `
+# Inputs
+# DOCKERFILE_DIR - Directory in which Dockerfile file is located.
+# DOCKER_RUN_SCRIPT - Script to run under docker (relative to grpc repo root)
+
+# Use image name based on Dockerfile location checksum
+DOCKER_IMAGE_NAME=$(basename $DOCKERFILE_DIR)_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ )
 
 # Make sure docker image has been built. Should be instantaneous if so.
-docker build -t $DOCKER_IMAGE_NAME tools/jenkins/grpc_jenkins_slave$docker_suffix
+docker build -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR
 
 # Choose random name for docker container
 CONTAINER_NAME="run_tests_$(uuidgen)"
@@ -76,7 +80,7 @@
   -w /var/local/git/grpc \
   --name=$CONTAINER_NAME \
   $DOCKER_IMAGE_NAME \
-  bash -l /var/local/jenkins/grpc/tools/jenkins/docker_run_tests.sh || DOCKER_FAILED="true"
+  bash -l "/var/local/jenkins/grpc/$DOCKER_RUN_SCRIPT" || DOCKER_FAILED="true"
 
 if [ "$XML_REPORT" != "" ]
 then
diff --git a/tools/jenkins/build_interop_image.sh b/tools/jenkins/build_interop_image.sh
index 7393706..28d5f31 100755
--- a/tools/jenkins/build_interop_image.sh
+++ b/tools/jenkins/build_interop_image.sh
@@ -71,10 +71,10 @@
 fi
 
 # Use image name based on Dockerfile checksum
-BASE_IMAGE=${BASE_NAME}_base:`sha1sum tools/jenkins/$BASE_NAME/Dockerfile | cut -f1 -d\ `
+BASE_IMAGE=${BASE_NAME}_base:`sha1sum tools/dockerfile/$BASE_NAME/Dockerfile | cut -f1 -d\ `
 
 # Make sure base docker image has been built. Should be instantaneous if so.
-docker build -t $BASE_IMAGE --force-rm=true tools/jenkins/$BASE_NAME || exit $?
+docker build -t $BASE_IMAGE --force-rm=true tools/dockerfile/$BASE_NAME || exit $?
 
 # Create a local branch so the child Docker script won't complain
 git branch -f jenkins-docker
@@ -92,7 +92,7 @@
   -v /tmp/ccache:/tmp/ccache \
   --name=$CONTAINER_NAME \
   $BASE_IMAGE \
-  bash -l /var/local/jenkins/grpc/tools/jenkins/$BASE_NAME/build_interop.sh \
+  bash -l /var/local/jenkins/grpc/tools/dockerfile/$BASE_NAME/build_interop.sh \
   && docker commit $CONTAINER_NAME $INTEROP_IMAGE \
   && echo "Successfully built image $INTEROP_IMAGE")
 EXITCODE=$?
diff --git a/tools/jenkins/build_interop_stress_image.sh b/tools/jenkins/build_interop_stress_image.sh
index 395eaa3..92f2dab 100755
--- a/tools/jenkins/build_interop_stress_image.sh
+++ b/tools/jenkins/build_interop_stress_image.sh
@@ -55,10 +55,10 @@
 fi
 
 # Use image name based on Dockerfile checksum
-BASE_IMAGE=${BASE_NAME}_base:`sha1sum tools/jenkins/$BASE_NAME/Dockerfile | cut -f1 -d\ `
+BASE_IMAGE=${BASE_NAME}_base:`sha1sum tools/dockerfile/$BASE_NAME/Dockerfile | cut -f1 -d\ `
 
 # Make sure base docker image has been built. Should be instantaneous if so.
-docker build -t $BASE_IMAGE --force-rm=true tools/jenkins/$BASE_NAME || exit $?
+docker build -t $BASE_IMAGE --force-rm=true tools/dockerfile/$BASE_NAME || exit $?
 
 # Create a local branch so the child Docker script won't complain
 git branch -f jenkins-docker
@@ -75,7 +75,7 @@
   -v /tmp/ccache:/tmp/ccache \
   --name=$CONTAINER_NAME \
   $BASE_IMAGE \
-  bash -l /var/local/jenkins/grpc/tools/jenkins/$BASE_NAME/build_interop_stress.sh \
+  bash -l /var/local/jenkins/grpc/tools/dockerfile/$BASE_NAME/build_interop_stress.sh \
   && docker commit $CONTAINER_NAME $INTEROP_IMAGE \
   && echo "Successfully built image $INTEROP_IMAGE")
 EXITCODE=$?
diff --git a/tools/jenkins/docker_run_tests.sh b/tools/jenkins/docker_run_tests.sh
index 148a0f5..26e5585 100755
--- a/tools/jenkins/docker_run_tests.sh
+++ b/tools/jenkins/docker_run_tests.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -43,8 +43,12 @@
 mkdir -p /var/local/git
 git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
 
-nvm use 0.12
-rvm use ruby-2.1
+nvm use 0.12 || true
+
+if [ -x "$(command -v rvm)" ]
+then
+  rvm use ruby-2.1
+fi
 
 mkdir -p reports
 
diff --git a/tools/jenkins/grpc_interop_http2/Dockerfile b/tools/jenkins/grpc_interop_http2/Dockerfile
deleted file mode 100644
index bb60f09..0000000
--- a/tools/jenkins/grpc_interop_http2/Dockerfile
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-FROM golang:1.4
-
-# Using login shell removes Go from path, so we add it.
-RUN ln -s /usr/src/go/bin/go /usr/local/bin
-
-# Define the default command.
-CMD ["bash"]
diff --git a/tools/jenkins/grpc_jenkins_slave/Dockerfile b/tools/jenkins/grpc_jenkins_slave/Dockerfile
deleted file mode 100644
index 48541b0..0000000
--- a/tools/jenkins/grpc_jenkins_slave/Dockerfile
+++ /dev/null
@@ -1,172 +0,0 @@
-# Copyright 2015-2016, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
-FROM debian:jessie
-
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
-  autoconf \
-  autotools-dev \
-  build-essential \
-  bzip2 \
-  ccache \
-  curl \
-  gcc \
-  gcc-multilib \
-  git \
-  golang \
-  gyp \
-  lcov \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
-  libtool \
-  make \
-  perl \
-  strace \
-  python-dev \
-  python-setuptools \
-  python-yaml \
-  telnet \
-  unzip \
-  wget \
-  zip && apt-get clean
-
-# Prepare ccache
-RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
-RUN ln -s /usr/bin/ccache /usr/local/bin/g++
-RUN ln -s /usr/bin/ccache /usr/local/bin/cc
-RUN ln -s /usr/bin/ccache /usr/local/bin/c++
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
-
-##################
-# C++ dependencies
-RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang
-
-#################
-# C# dependencies
-
-# Update to a newer version of mono
-RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-
-# Install dependencies
-RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
-    mono-devel \
-    nunit \
-    nunit-console \
-    monodevelop
-
-# Download NuGet
-RUN cd /var/local && wget www.nuget.org/NuGet.exe
-ENV NUGET mono /var/local/NuGet.exe
-
-# TODO(jtattermusch): add dependencies for other languages
-
-##################
-# Node dependencies
-
-# Install nvm
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
-RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
-
-##################
-# Ruby dependencies
-
-# Install rvm
-RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
-RUN \curl -sSL https://get.rvm.io | bash -s stable
-
-# Install Ruby 2.1
-RUN /bin/bash -l -c "rvm install ruby-2.1"
-RUN /bin/bash -l -c "rvm use --default ruby-2.1"
-RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
-RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
-RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
-RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
-
-##################
-# Python dependencies
-
-# Install dependencies
-
-RUN apt-get update && apt-get install -y \
-    python-all-dev \
-    python3-all-dev \
-    python-pip
-
-# Install Python packages from PyPI
-RUN pip install pip --upgrade
-RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 tox
-
-# For sanity test
-RUN pip install simplejson mako
-
-##################
-# PHP dependencies
-
-# Install dependencies
-
-RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
-
-RUN apt-get update && apt-get install -y \
-    git php5 php5-dev phpunit unzip
-
-##################
-# Zookeeper dependencies
-
-# Install dependencies
-
-RUN apt-get install -y libzookeeper-mt-dev
-
-##################
-# Docker "inception".
-# Note this is quite the ugly hack.
-# This makes sure that the docker binary we inject has its dependencies.
-RUN curl https://get.docker.com/ | sh
-RUN apt-get remove --purge -y docker-engine
-
-RUN mkdir /var/local/jenkins
-
-# Define the default command.
-CMD ["bash"]
diff --git a/tools/jenkins/run_distribution.sh b/tools/jenkins/run_distribution.sh
index 64c60f1..446ce16 100755
--- a/tools/jenkins/run_distribution.sh
+++ b/tools/jenkins/run_distribution.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -47,11 +47,11 @@
 
   if [ "$dist_channel" == "homebrew" ]; then
 
-    sha1=$(sha1sum tools/jenkins/grpc_linuxbrew/Dockerfile | cut -f1 -d\ )
+    sha1=$(sha1sum tools/dockerfile/grpc_linuxbrew/Dockerfile | cut -f1 -d\ )
     DOCKER_IMAGE_NAME=grpc_linuxbrew_$sha1
 
     # build docker image, contains all pre-requisites
-    docker build -t $DOCKER_IMAGE_NAME tools/jenkins/grpc_linuxbrew
+    docker build -t $DOCKER_IMAGE_NAME tools/dockerfile/grpc_linuxbrew
 
     # run per-language homebrew installation script
     docker run --rm=true $DOCKER_IMAGE_NAME bash -l \
diff --git a/tools/jenkins/run_jenkins.sh b/tools/jenkins/run_jenkins.sh
index 49b2fa5..4cb31e6 100755
--- a/tools/jenkins/run_jenkins.sh
+++ b/tools/jenkins/run_jenkins.sh
@@ -39,52 +39,18 @@
 # NOTE: No empty lines should appear in this file before igncr is set!
 set -ex -o igncr || set -ex
 
-# Grabbing the machine's architecture
-arch=`uname -m`
-
-case $platform in
-  i386)
-    arch="i386"
-    platform="linux"
-    docker_suffix=_32bits
-    ;;
-esac
-
 if [ "$platform" == "linux" ]
 then
-  echo "building $language on Linux"
-
-  ./tools/run_tests/run_tests.py --use_docker -t -l $language -c $config -x report.xml -j 3 $@ || TESTS_FAILED="true"
-
-elif [ "$platform" == "windows" ]
-then
-  echo "building $language on Windows"
-
-  # Prevent msbuild from picking up "platform" env variable, which would break the build
-  unset platform
-
-  python tools/run_tests/run_tests.py -t -l $language -c $config -x report.xml -j 3 $@ || TESTS_FAILED="true"
-
-elif [ "$platform" == "macos" ]
-then
-  echo "building $language on MacOS"
-
-  # Prevent msbuild from picking up "platform" env variable, which would break the build
-  unset platform
-
-  ./tools/run_tests/run_tests.py -t -l $language -c $config -x report.xml -j 3 $@ || TESTS_FAILED="true"
-
+  USE_DOCKER_MAYBE="--use_docker"
 elif [ "$platform" == "freebsd" ]
 then
-  echo "building $language on FreeBSD"
-
-  MAKE=gmake ./tools/run_tests/run_tests.py -t -l $language -c $config -x report.xml -j 3 $@ || TESTS_FAILED="true"
-
-else
-  echo "Unknown platform $platform"
-  exit 1
+  export MAKE=gmake
 fi
 
+unset platform  # variable named 'platform' breaks the windows build
+
+python tools/run_tests/run_tests.py $USE_DOCKER_MAYBE -t -l $language -c $config -x report.xml -j 2 $@ || TESTS_FAILED="true"
+
 if [ ! -e reports/index.html ]
 then
   mkdir -p reports
diff --git a/tools/jenkins/run_portability.sh b/tools/jenkins/run_portability.sh
index afce4ad..82aaa93 100755
--- a/tools/jenkins/run_portability.sh
+++ b/tools/jenkins/run_portability.sh
@@ -1,5 +1,5 @@
 #!/usr/bin/env bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -48,13 +48,10 @@
 curr_compiler=${parts[2]}
 
 config='dbg'
-maybe_build_only='--build_only'
 
-if [ "$curr_platform" == "windows" ]
+if [ "$curr_platform" == "linux" ]
 then
-  win_arch="windows_${curr_arch}"
-  python tools/run_tests/run_tests.py -t -l $language -c $config --arch ${win_arch} --compiler ${curr_compiler} ${maybe_build_only} -x report.xml $@
-else
-  echo "Unsupported scenario."
-  exit 1
+  USE_DOCKER_MAYBE="--use_docker"
 fi
+
+python tools/run_tests/run_tests.py $USE_DOCKER_MAYBE -t -l $language -c $config --arch ${curr_arch} --compiler ${curr_compiler} -x report.xml -j 3 $@
\ No newline at end of file
diff --git a/tools/run_tests/build_artifacts.py b/tools/run_tests/build_artifacts.py
index ff9dd47..0337f1b 100755
--- a/tools/run_tests/build_artifacts.py
+++ b/tools/run_tests/build_artifacts.py
@@ -135,7 +135,7 @@
                  'EMBED_ZLIB': 'true'}
       if self.platform == 'linux':
         return create_docker_jobspec(self.name,
-            'tools/jenkins/grpc_artifact_linux_%s' % self.arch,
+            'tools/dockerfile/grpc_artifact_linux_%s' % self.arch,
             'tools/run_tests/build_artifact_csharp.sh')
       else:
         environ.update(macos_arch_env(self.arch))
diff --git a/tools/run_tests/build_node.sh b/tools/run_tests/build_node.sh
index faa7b62..8f2ab44 100755
--- a/tools/run_tests/build_node.sh
+++ b/tools/run_tests/build_node.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -36,4 +36,4 @@
 # change to grpc repo root
 cd $(dirname $0)/../..
 
-npm install --unsafe-perm
+npm install --unsafe-perm --build-from-source
diff --git a/tools/run_tests/configs.json b/tools/run_tests/configs.json
index 769942d..d508c63 100644
--- a/tools/run_tests/configs.json
+++ b/tools/run_tests/configs.json
@@ -59,7 +59,7 @@
   }, 
   {
     "config": "msan", 
-    "timeout_multiplier": 1.5
+    "timeout_multiplier": 2
   }, 
   {
     "config": "mutrace"
diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py
index beeb99c..adf178b 100755
--- a/tools/run_tests/jobset.py
+++ b/tools/run_tests/jobset.py
@@ -360,7 +360,7 @@
       if self.cancelled(): return False
       current_cpu_cost = self.cpu_cost()
       if current_cpu_cost == 0: break
-      if current_cpu_cost + spec.cpu_cost < self._maxjobs: break
+      if current_cpu_cost + spec.cpu_cost <= self._maxjobs: break
       self.reap()
     if self.cancelled(): return False
     if spec.hash_targets:
diff --git a/tools/run_tests/run_node.sh b/tools/run_tests/run_node.sh
index fff579f..f93c9c3 100755
--- a/tools/run_tests/run_node.sh
+++ b/tools/run_tests/run_node.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -51,5 +51,5 @@
   echo '<html><head><meta http-equiv="refresh" content="0;URL=lcov-report/index.html"></head></html>' > \
     ../reports/node_coverage/index.html
 else
-  JUNIT_REPORT_PATH=src/node/reports.xml JUNIT_REPORT_STACK=1 ./node_modules/.bin/mocha --reporter mocha-jenkins-reporter src/node/test || true
+  JUNIT_REPORT_PATH=src/node/reports.xml JUNIT_REPORT_STACK=1 ./node_modules/.bin/mocha --reporter mocha-jenkins-reporter src/node/test
 fi
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index f8b0102..fa4a37a 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -151,9 +151,9 @@
   def make_targets(self, test_regex):
     if platform_string() != 'windows' and test_regex != '.*':
       # use the regex to minimize the number of things to build
-      return [target['name']
+      return [os.path.basename(target['name'])
               for target in get_c_tests(False, self.test_lang)
-              if re.search(test_regex, target['name'])]
+              if re.search(test_regex, '/' + target['name'])]
     if platform_string() == 'windows':
       # don't build tools on windows just yet
       return ['buildtests_%s' % self.make_target]
@@ -183,6 +183,9 @@
   def supports_multi_config(self):
     return True
 
+  def dockerfile_dir(self, config, arch):
+    return None
+
   def __str__(self):
     return self.make_target
 
@@ -215,6 +218,9 @@
   def supports_multi_config(self):
     return False
 
+  def dockerfile_dir(self, config, arch):
+    return None
+
   def __str__(self):
     return 'node'
 
@@ -246,6 +252,9 @@
   def supports_multi_config(self):
     return False
 
+  def dockerfile_dir(self, config, arch):
+    return None
+
   def __str__(self):
     return 'php'
 
@@ -299,6 +308,9 @@
   def supports_multi_config(self):
     return False
 
+  def dockerfile_dir(self, config, arch):
+    return None
+
   def __str__(self):
     return 'python'
 
@@ -330,6 +342,9 @@
   def supports_multi_config(self):
     return False
 
+  def dockerfile_dir(self, config, arch):
+    return None
+
   def __str__(self):
     return 'ruby'
 
@@ -412,6 +427,9 @@
   def supports_multi_config(self):
     return False
 
+  def dockerfile_dir(self, config, arch):
+    return None
+
   def __str__(self):
     return 'csharp'
 
@@ -443,6 +461,9 @@
   def supports_multi_config(self):
     return False
 
+  def dockerfile_dir(self, config, arch):
+    return None
+
   def __str__(self):
     return 'objc'
 
@@ -451,8 +472,10 @@
 
   def test_specs(self, config, args):
     import yaml
-    with open('tools/run_tests/sanity_tests.yaml', 'r') as f:
-      return [config.job_spec([cmd['script']], None, timeout_seconds=None, environ={'TEST': 'true'}, cpu_cost=cmd.get('cpu_cost', 1))
+    with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
+      return [config.job_spec(cmd['script'].split(), None,
+                              timeout_seconds=None, environ={'TEST': 'true'},
+                              cpu_cost=cmd.get('cpu_cost', 1))
               for cmd in yaml.load(f)]
 
   def pre_build_steps(self):
@@ -476,6 +499,9 @@
   def supports_multi_config(self):
     return False
 
+  def dockerfile_dir(self, config, arch):
+    return 'tools/dockerfile/grpc_sanity'
+
   def __str__(self):
     return 'sanity'
 
@@ -506,6 +532,9 @@
   def supports_multi_config(self):
     return True
 
+  def dockerfile_dir(self, config, arch):
+    return None
+
   def __str__(self):
     return self.make_target
 
@@ -538,15 +567,37 @@
 
 def _windows_arch_option(arch):
   """Returns msbuild cmdline option for selected architecture."""
-  if arch == 'default' or arch == 'windows_x86':
+  if arch == 'default' or arch == 'x86':
     return '/p:Platform=Win32'
-  elif arch == 'windows_x64':
+  elif arch == 'x64':
     return '/p:Platform=x64'
   else:
-    print 'Architecture %s not supported on current platform.' % arch
+    print 'Architecture %s not supported.' % arch
     sys.exit(1)
 
-    
+
+def _check_arch_option(arch):
+  """Checks that architecture option is valid."""
+  if platform_string() == 'windows':
+    _windows_arch_option(arch)
+  elif platform_string() == 'linux':
+    # On linux, we need to be running under docker with the right architecture.
+    runtime_arch = platform.architecture()[0]
+    if arch == 'default':
+      return
+    elif runtime_arch == '64bit' and arch == 'x64':
+      return
+    elif runtime_arch == '32bit' and arch == 'x86':
+      return
+    else:
+      print 'Architecture %s does not match current runtime architecture.' % arch
+      sys.exit(1)
+  else:
+    if args.arch != 'default':
+      print 'Architecture %s not supported on current platform.' % args.arch
+      sys.exit(1)
+
+
 def _windows_build_bat(compiler):
   """Returns name of build.bat for selected compiler."""
   if compiler == 'default' or compiler == 'vs2013':
@@ -558,8 +609,8 @@
   else:
     print 'Compiler %s not supported.' % compiler
     sys.exit(1)
-    
-    
+
+
 def _windows_toolset_option(compiler):
   """Returns msbuild PlatformToolset for selected compiler."""
   if compiler == 'default' or compiler == 'vs2013':
@@ -571,7 +622,21 @@
   else:
     print 'Compiler %s not supported.' % compiler
     sys.exit(1)
-   
+
+
+def _get_dockerfile_dir(language, cfg, arch):
+  """Returns dockerfile to use"""
+  custom = language.dockerfile_dir(cfg, arch)
+  if custom:
+    return custom
+  else:
+    if arch == 'default' or arch == 'x64':
+      return 'tools/dockerfile/grpc_tests_multilang_x64'
+    elif arch == 'x86':
+      return 'tools/dockerfile/grpc_tests_multilang_x86'
+    else:
+      print 'Architecture %s not supported with current settings.' % arch
+      sys.exit(1)
 
 def runs_per_test_type(arg_str):
     """Auxilary function to parse the "runs_per_test" flag.
@@ -638,7 +703,7 @@
                   const=True,
                   help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
 argp.add_argument('--arch',
-                  choices=['default', 'windows_x86', 'windows_x64'],
+                  choices=['default', 'x86', 'x64'],
                   default='default',
                   help='Selects architecture to target. For some platforms "default" is the only supported choice.')
 argp.add_argument('--compiler',
@@ -662,36 +727,6 @@
 
 jobset.measure_cpu_costs = args.measure_cpu_costs
 
-if args.use_docker:
-  if not args.travis:
-    print 'Seen --use_docker flag, will run tests under docker.'
-    print
-    print 'IMPORTANT: The changes you are testing need to be locally committed'
-    print 'because only the committed changes in the current branch will be'
-    print 'copied to the docker environment.'
-    time.sleep(5)
-
-  child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
-  run_tests_cmd = 'tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
-
-  # TODO(jtattermusch): revisit if we need special handling for arch here
-  # set arch command prefix in case we are working with different arch.
-  arch_env = os.getenv('arch')
-  if arch_env:
-    run_test_cmd = 'arch %s %s' % (arch_env, run_test_cmd)
-
-  env = os.environ.copy()
-  env['RUN_TESTS_COMMAND'] = run_tests_cmd
-  if args.xml_report:
-    env['XML_REPORT'] = args.xml_report
-  if not args.travis:
-    env['TTY_FLAG'] = '-t'  # enables Ctrl-C when not on Jenkins.
-
-  subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
-                        shell=True,
-                        env=env)
-  sys.exit(0)
-
 # update submodules if necessary
 need_to_regenerate_projects = False
 for spec in args.update_submodules:
@@ -755,16 +790,46 @@
   else:
     language_make_options = next(iter(languages)).make_options()
 
-if platform_string() != 'windows':
-  if args.arch != 'default':
-    print 'Architecture %s not supported on current platform.' % args.arch
-    sys.exit(1)
-  if args.compiler != 'default':
+if len(languages) != 1 or len(build_configs) != 1:
+  print 'Multi-language and multi-config testing is not supported.'
+  sys.exit(1)
+
+if args.use_docker:
+  if not args.travis:
+    print 'Seen --use_docker flag, will run tests under docker.'
+    print
+    print 'IMPORTANT: The changes you are testing need to be locally committed'
+    print 'because only the committed changes in the current branch will be'
+    print 'copied to the docker environment.'
+    time.sleep(5)
+
+  child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
+  run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
+
+  env = os.environ.copy()
+  env['RUN_TESTS_COMMAND'] = run_tests_cmd
+  env['DOCKERFILE_DIR'] = _get_dockerfile_dir(next(iter(languages)),
+                                              next(iter(build_configs)),
+                                              args.arch)
+  env['DOCKER_RUN_SCRIPT'] = 'tools/jenkins/docker_run_tests.sh'
+  if args.xml_report:
+    env['XML_REPORT'] = args.xml_report
+  if not args.travis:
+    env['TTY_FLAG'] = '-t'  # enables Ctrl-C when not on Jenkins.
+
+  subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
+                        shell=True,
+                        env=env)
+  sys.exit(0)
+
+if platform_string() != 'windows' and args.compiler != 'default':
     print 'Compiler %s not supported on current platform.' % args.compiler
     sys.exit(1)
 
-if platform_string() == 'windows':
-  def make_jobspec(cfg, targets, makefile='Makefile'):
+_check_arch_option(args.arch)
+
+def make_jobspec(cfg, targets, makefile='Makefile'):
+  if platform_string() == 'windows':
     extra_args = []
     # better do parallel compilation
     # empirically /m:2 gives the best performance/price and should prevent
@@ -782,8 +847,7 @@
                       language_make_options,
                       shell=True, timeout_seconds=None)
       for target in targets]
-else:
-  def make_jobspec(cfg, targets, makefile='Makefile'):
+  else:
     if targets:
       return [jobset.JobSpec([os.getenv('MAKE', 'make'),
                               '-f', makefile,
@@ -796,6 +860,7 @@
                              timeout_seconds=None)]
     else:
       return []
+
 make_targets = {}
 for l in languages:
   makefile = l.makefile_name()
diff --git a/tools/run_tests/check_cache_mk.sh b/tools/run_tests/sanity/check_cache_mk.sh
similarity index 100%
rename from tools/run_tests/check_cache_mk.sh
rename to tools/run_tests/sanity/check_cache_mk.sh
diff --git a/tools/run_tests/check_sources_and_headers.py b/tools/run_tests/sanity/check_sources_and_headers.py
similarity index 66%
rename from tools/run_tests/check_sources_and_headers.py
rename to tools/run_tests/sanity/check_sources_and_headers.py
index 50574f4..3974af0 100755
--- a/tools/run_tests/check_sources_and_headers.py
+++ b/tools/run_tests/sanity/check_sources_and_headers.py
@@ -33,9 +33,9 @@
 import re
 import sys
 
-root = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
+root = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../../..'))
 with open(os.path.join(root, 'tools', 'run_tests', 'sources_and_headers.json')) as f:
-	js = json.loads(f.read())
+  js = json.loads(f.read())
 
 re_inc1 = re.compile(r'^#\s*include\s*"([^"]*)"')
 assert re_inc1.match('#include "foo"').group(1) == 'foo'
@@ -43,41 +43,41 @@
 assert re_inc2.match('#include <grpc++/foo>').group(1) == 'grpc++/foo'
 
 def get_target(name):
-	for target in js:
-		if target['name'] == name:
-			return target
-	assert False, 'no target %s' % name
+  for target in js:
+    if target['name'] == name:
+      return target
+  assert False, 'no target %s' % name
 
 def target_has_header(target, name):
-#	print target['name'], name
-	if name in target['headers']:
-		return True
-	for dep in target['deps']:
-		if target_has_header(get_target(dep), name):
-			return True
-	if name == 'src/core/profiling/stap_probes.h':
-		return True
-	return False
+  # print target['name'], name
+  if name in target['headers']:
+    return True
+  for dep in target['deps']:
+    if target_has_header(get_target(dep), name):
+      return True
+  if name == 'src/core/profiling/stap_probes.h':
+    return True
+  return False
 
 errors = 0
 for target in js:
-	for fn in target['src']:
-		with open(os.path.join(root, fn)) as f:
-			src = f.read().splitlines()
-		for line in src:
-			m = re_inc1.match(line)
-			if m:
-				if not target_has_header(target, m.group(1)):
-					print (
-						'target %s (%s) does not name header %s as a dependency' % (
-							target['name'], fn, m.group(1)))
-					errors += 1
-			m = re_inc2.match(line)
-			if m:
-				if not target_has_header(target, 'include/' + m.group(1)):
-					print (
-						'target %s (%s) does not name header %s as a dependency' % (
-							target['name'], fn, m.group(1)))
-					errors += 1
+  for fn in target['src']:
+    with open(os.path.join(root, fn)) as f:
+      src = f.read().splitlines()
+    for line in src:
+      m = re_inc1.match(line)
+      if m:
+        if not target_has_header(target, m.group(1)):
+          print (
+            'target %s (%s) does not name header %s as a dependency' % (
+              target['name'], fn, m.group(1)))
+          errors += 1
+      m = re_inc2.match(line)
+      if m:
+        if not target_has_header(target, 'include/' + m.group(1)):
+          print (
+            'target %s (%s) does not name header %s as a dependency' % (
+              target['name'], fn, m.group(1)))
+          errors += 1
 
 assert errors == 0
diff --git a/tools/run_tests/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
similarity index 98%
rename from tools/run_tests/check_submodules.sh
rename to tools/run_tests/sanity/check_submodules.sh
index b4ca4fa..f49230e 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -34,7 +34,7 @@
 
 export TEST=true
 
-cd `dirname $0`/../..
+cd `dirname $0`/../../..
 
 submodules=`mktemp /tmp/submXXXXXX`
 want_submodules=`mktemp /tmp/submXXXXXX`
diff --git a/tools/run_tests/sanity/sanity_tests.yaml b/tools/run_tests/sanity/sanity_tests.yaml
new file mode 100644
index 0000000..809e6ce
--- /dev/null
+++ b/tools/run_tests/sanity/sanity_tests.yaml
@@ -0,0 +1,9 @@
+# a set of tests that are run in parallel for sanity tests
+- script: tools/run_tests/sanity/check_sources_and_headers.py
+- script: tools/run_tests/sanity/check_submodules.sh
+- script: tools/run_tests/sanity/check_cache_mk.sh
+- script: tools/buildgen/generate_projects.sh -j 3
+  cpu_cost: 3
+- script: tools/distrib/check_copyright.py
+- script: tools/distrib/clang_format_code.sh
+- script: tools/distrib/check_trailing_newlines.sh
diff --git a/tools/run_tests/sanity_tests.yaml b/tools/run_tests/sanity_tests.yaml
deleted file mode 100644
index 160acde..0000000
--- a/tools/run_tests/sanity_tests.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-# a set of tests that are run in parallel for sanity tests
-- script: tools/run_tests/check_sources_and_headers.py
-- script: tools/run_tests/check_submodules.sh
-- script: tools/run_tests/check_cache_mk.sh
-- script: tools/buildgen/generate_projects.sh
-  cpu_cost: 100
-- script: tools/distrib/check_copyright.py
-- script: tools/distrib/clang_format_code.sh
-- script: tools/distrib/check_trailing_newlines.sh
diff --git a/tools/tsan_suppressions.txt b/tools/tsan_suppressions.txt
index 65e7e2e..09e68cd 100644
--- a/tools/tsan_suppressions.txt
+++ b/tools/tsan_suppressions.txt
@@ -5,4 +5,4 @@
 # https://www.mail-archive.com/openssl-dev@openssl.org/msg09019.html
 race:ssleay_rand_add
 race:ssleay_rand_bytes
-
+race:__sleep_for