Branch merge
diff --git a/Doc/library/cmd.rst b/Doc/library/cmd.rst
index c1cda5b..0c43bb8 100644
--- a/Doc/library/cmd.rst
+++ b/Doc/library/cmd.rst
@@ -247,7 +247,7 @@
             right(*parse(arg))
         def do_left(self, arg):
             'Turn turtle left by given number of degrees:  LEFT 90'
-            right(*parse(arg))
+            left(*parse(arg))
         def do_goto(self, arg):
             'Move turtle to an absolute position with changing orientation.  GOTO 100 200'
             goto(*parse(arg))
diff --git a/Doc/library/zlib.rst b/Doc/library/zlib.rst
index 54835e7..9f8eb26 100644
--- a/Doc/library/zlib.rst
+++ b/Doc/library/zlib.rst
@@ -19,7 +19,7 @@
 information.
 
 For reading and writing ``.gz`` files see the :mod:`gzip` module. For
-other archive formats, see the :mod:`bz2`, :mod:`zipfile`, and
+other related file formats, see the :mod:`bz2`, :mod:`zipfile`, and
 :mod:`tarfile` modules.
 
 The available exception and functions in this module are:
@@ -122,6 +122,7 @@
    won't fit into memory at once.  The *wbits* parameter controls the size of the
    window buffer.
 
+
 Compression objects support the following methods:
 
 
@@ -217,6 +218,24 @@
    seeks into the stream at a future point.
 
 
+Information about the version of the zlib library in use is available through
+the following constants:
+
+
+.. data:: ZLIB_VERSION
+
+   The version string of the zlib library that was used for building the module.
+   This may be different from the zlib library actually used at runtime, which
+   is available as :const:`ZLIB_RUNTIME_VERSION`.
+
+
+.. data:: ZLIB_RUNTIME_VERSION
+
+   The version string of the zlib library actually loaded by the interpreter.
+
+   .. versionadded:: 3.3
+
+
 .. seealso::
 
    Module :mod:`gzip`
diff --git a/Lib/bz2.py b/Lib/bz2.py
index cc71ae0..cbf5233 100644
--- a/Lib/bz2.py
+++ b/Lib/bz2.py
@@ -75,11 +75,11 @@
         elif mode in ("w", "wb"):
             mode = "wb"
             mode_code = _MODE_WRITE
-            self._compressor = BZ2Compressor()
+            self._compressor = BZ2Compressor(compresslevel)
         elif mode in ("a", "ab"):
             mode = "ab"
             mode_code = _MODE_WRITE
-            self._compressor = BZ2Compressor()
+            self._compressor = BZ2Compressor(compresslevel)
         else:
             raise ValueError("Invalid mode: {!r}".format(mode))
 
diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py
index 2007e68..e5e0277 100644
--- a/Lib/collections/__init__.py
+++ b/Lib/collections/__init__.py
@@ -1,5 +1,5 @@
 __all__ = ['deque', 'defaultdict', 'namedtuple', 'UserDict', 'UserList',
-            'UserString', 'Counter', 'OrderedDict']
+            'UserString', 'Counter', 'OrderedDict', 'ChainMap']
 
 # For backwards compatibility, continue to make the collections ABCs
 # available through the collections module.
diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py
index 5a7d342..d003238 100644
--- a/Lib/test/test_bz2.py
+++ b/Lib/test/test_bz2.py
@@ -224,6 +224,13 @@
         with open(self.filename, 'rb') as f:
             self.assertEqual(self.decompress(f.read()), self.TEXT)
 
+    def testWriteNonDefaultCompressLevel(self):
+        expected = bz2.compress(self.TEXT, compresslevel=5)
+        with BZ2File(self.filename, "w", compresslevel=5) as bz2f:
+            bz2f.write(self.TEXT)
+        with open(self.filename, "rb") as f:
+            self.assertEqual(f.read(), expected)
+
     def testWriteLines(self):
         with BZ2File(self.filename, "w") as bz2f:
             self.assertRaises(TypeError, bz2f.writelines)
diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py
index 7a7805d..3f8a9a2 100644
--- a/Lib/test/test_multiprocessing.py
+++ b/Lib/test/test_multiprocessing.py
@@ -296,6 +296,7 @@
         p = self.Process(target=time.sleep, args=(DELTA,))
         self.assertNotIn(p, self.active_children())
 
+        p.daemon = True
         p.start()
         self.assertIn(p, self.active_children())
 
@@ -386,6 +387,7 @@
 
     def test_subclassing(self):
         uppercaser = _UpperCaser()
+        uppercaser.daemon = True
         uppercaser.start()
         self.assertEqual(uppercaser.submit('hello'), 'HELLO')
         self.assertEqual(uppercaser.submit('world'), 'WORLD')
@@ -564,6 +566,7 @@
 
         # fork process
         p = self.Process(target=self._test_fork, args=(queue,))
+        p.daemon = True
         p.start()
 
         # check that all expected items are in the queue
@@ -604,6 +607,7 @@
                    for i in range(4)]
 
         for p in workers:
+            p.daemon = True
             p.start()
 
         for i in range(10):
@@ -874,7 +878,9 @@
 
         #self.assertEqual(event.is_set(), False)
 
-        self.Process(target=self._test_event, args=(event,)).start()
+        p = self.Process(target=self._test_event, args=(event,))
+        p.daemon = True
+        p.start()
         self.assertEqual(wait(), True)
 
 #
@@ -914,6 +920,7 @@
             self.assertEqual(sv.value, cv[1])
 
         proc = self.Process(target=self._test, args=(values,))
+        proc.daemon = True
         proc.start()
         proc.join()
 
@@ -977,6 +984,7 @@
         self.f(seq)
 
         p = self.Process(target=self.f, args=(arr,))
+        p.daemon = True
         p.start()
         p.join()
 
@@ -1381,6 +1389,7 @@
         manager.start()
 
         p = self.Process(target=self._putter, args=(manager.address, authkey))
+        p.daemon = True
         p.start()
 
         manager2 = QueueManager2(
@@ -1422,6 +1431,7 @@
         manager.start()
 
         p = self.Process(target=self._putter, args=(manager.address, authkey))
+        p.daemon = True
         p.start()
         queue = manager.get_queue()
         self.assertEqual(queue.get(), 'hello world')
@@ -1554,6 +1564,7 @@
         conn, child_conn = self.Pipe()
 
         p = self.Process(target=self._echo, args=(child_conn,))
+        p.daemon = True
         p.start()
         child_conn.close()    # this might complete before child initializes
 
@@ -1626,6 +1637,7 @@
         conn, child_conn = self.Pipe(duplex=True)
 
         p = self.Process(target=self._writefd, args=(child_conn, b"foo"))
+        p.daemon = True
         p.start()
         with open(test.support.TESTFN, "wb") as f:
             fd = f.fileno()
@@ -1649,6 +1661,7 @@
         conn, child_conn = self.Pipe(duplex=True)
 
         p = self.Process(target=self._writefd, args=(child_conn, b"bar", True))
+        p.daemon = True
         p.start()
         with open(test.support.TESTFN, "wb") as f:
             fd = f.fileno()
@@ -1737,11 +1750,13 @@
 
         lconn, lconn0 = self.Pipe()
         lp = self.Process(target=self._listener, args=(lconn0, families))
+        lp.daemon = True
         lp.start()
         lconn0.close()
 
         rconn, rconn0 = self.Pipe()
         rp = self.Process(target=self._remote, args=(rconn0,))
+        rp.daemon = True
         rp.start()
         rconn0.close()
 
@@ -1879,6 +1894,7 @@
         string.value = latin('hello')
 
         p = self.Process(target=self._double, args=(x, y, foo, arr, string))
+        p.daemon = True
         p.start()
         p.join()
 
@@ -1951,6 +1967,7 @@
         conn, child_conn = self.Pipe()
 
         p = self.Process(target=self._test_finalize, args=(child_conn,))
+        p.daemon = True
         p.start()
         p.join()
 
@@ -2020,12 +2037,16 @@
         reader, writer = multiprocessing.Pipe(duplex=False)
 
         logger.setLevel(LEVEL1)
-        self.Process(target=self._test_level, args=(writer,)).start()
+        p = self.Process(target=self._test_level, args=(writer,))
+        p.daemon = True
+        p.start()
         self.assertEqual(LEVEL1, reader.recv())
 
         logger.setLevel(logging.NOTSET)
         root_logger.setLevel(LEVEL2)
-        self.Process(target=self._test_level, args=(writer,)).start()
+        p = self.Process(target=self._test_level, args=(writer,))
+        p.daemon = True
+        p.start()
         self.assertEqual(LEVEL2, reader.recv())
 
         root_logger.setLevel(root_level)
@@ -2217,6 +2238,7 @@
 def _TestProcess(q):
     queue = multiprocessing.Queue()
     subProc = multiprocessing.Process(target=_ThisSubProcess, args=(queue,))
+    subProc.daemon = True
     subProc.start()
     subProc.join()
 
diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py
index 1af6cf4..f70688d 100644
--- a/Lib/test/test_posix.py
+++ b/Lib/test/test_posix.py
@@ -862,12 +862,12 @@
         mine = posix.sched_getscheduler(0)
         self.assertIn(mine, possible_schedulers)
         try:
-            init = posix.sched_getscheduler(1)
+            parent = posix.sched_getscheduler(os.getppid())
         except OSError as e:
-            if e.errno != errno.EPERM and e.errno != errno.ESRCH:
+            if e.errno != errno.EPERM:
                 raise
         else:
-            self.assertIn(init, possible_schedulers)
+            self.assertIn(parent, possible_schedulers)
         self.assertRaises(OSError, posix.sched_getscheduler, -1)
         self.assertRaises(OSError, posix.sched_getparam, -1)
         param = posix.sched_getparam(0)
diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py
index dddde47..8d137ac 100644
--- a/Lib/test/test_zlib.py
+++ b/Lib/test/test_zlib.py
@@ -13,6 +13,17 @@
     mmap = None
 
 
+class VersionTestCase(unittest.TestCase):
+
+    def test_library_version(self):
+        # On the build system, ZLIB_RUNTIME_VERSION should match ZLIB_VERSION.
+        # ZLIB_RUNTIME_VERSION is the actual library version while ZLIB_VERSION
+        # is the version from the header file. On the build system, the headers
+        # should match with the library exactly. At runtime, only the first
+        # digit is required to match.
+        self.assertEqual(zlib.ZLIB_RUNTIME_VERSION, zlib.ZLIB_VERSION)
+
+
 class ChecksumTestCase(unittest.TestCase):
     # checksum test cases
     def test_crc32start(self):
@@ -647,6 +658,7 @@
 
 def test_main():
     support.run_unittest(
+        VersionTestCase,
         ChecksumTestCase,
         ChecksumBigBufferTestCase,
         ExceptionTestCase,
diff --git a/Misc/NEWS b/Misc/NEWS
index 3d35823..7218bfd 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -274,6 +274,11 @@
 Library
 -------
 
+- Issue #12306: Expose the runtime version of the zlib C library as a constant,
+  ZLIB_RUNTIME_VERSION, in the zlib module. Patch by Torsten Landschoff.
+
+- Issue #12959: Add collections.ChainMap to collections.__all__.
+ 
 - Issue #8933: distutils' PKG-INFO files and packaging's METADATA files will
   now correctly report Metadata-Version: 1.1 instead of 1.0 if a Classifier or
   Download-URL field is present.
@@ -1269,6 +1274,9 @@
 Extension Modules
 -----------------
 
+- Issue #12950: Fix passing file descriptors in multiprocessing, under
+  OpenIndiana/Illumos.
+
 - Issue #12764: Fix a crash in ctypes when the name of a Structure field is not
   a string.
 
diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c
index 1987b95..f6c2259 100644
--- a/Modules/_multiprocessing/multiprocessing.c
+++ b/Modules/_multiprocessing/multiprocessing.c
@@ -86,31 +86,37 @@
 /* Functions for transferring file descriptors between processes.
    Reimplements some of the functionality of the fdcred
    module at http://www.mca-ltd.com/resources/fdcred_1.tgz. */
+/* Based in http://resin.csoft.net/cgi-bin/man.cgi?section=3&topic=CMSG_DATA */
 
 static PyObject *
 multiprocessing_sendfd(PyObject *self, PyObject *args)
 {
     int conn, fd, res;
-    char dummy_char;
-    char buf[CMSG_SPACE(sizeof(int))];
-    struct msghdr msg = {0};
     struct iovec dummy_iov;
+    char dummy_char;
+    struct msghdr msg;
     struct cmsghdr *cmsg;
+    union {
+        struct cmsghdr hdr;
+        unsigned char buf[CMSG_SPACE(sizeof(int))];
+    } cmsgbuf;
 
     if (!PyArg_ParseTuple(args, "ii", &conn, &fd))
         return NULL;
 
     dummy_iov.iov_base = &dummy_char;
     dummy_iov.iov_len = 1;
-    msg.msg_control = buf;
-    msg.msg_controllen = sizeof(buf);
+
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_control = &cmsgbuf.buf;
+    msg.msg_controllen = sizeof(cmsgbuf.buf);
     msg.msg_iov = &dummy_iov;
     msg.msg_iovlen = 1;
+
     cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
     cmsg->cmsg_level = SOL_SOCKET;
     cmsg->cmsg_type = SCM_RIGHTS;
-    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
-    msg.msg_controllen = cmsg->cmsg_len;
     * (int *) CMSG_DATA(cmsg) = fd;
 
     Py_BEGIN_ALLOW_THREADS
@@ -127,20 +133,26 @@
 {
     int conn, fd, res;
     char dummy_char;
-    char buf[CMSG_SPACE(sizeof(int))];
-    struct msghdr msg = {0};
     struct iovec dummy_iov;
+    struct msghdr msg = {0};
     struct cmsghdr *cmsg;
+    union {
+        struct cmsghdr hdr;
+        unsigned char buf[CMSG_SPACE(sizeof(int))];
+    } cmsgbuf;
 
     if (!PyArg_ParseTuple(args, "i", &conn))
         return NULL;
 
     dummy_iov.iov_base = &dummy_char;
     dummy_iov.iov_len = 1;
-    msg.msg_control = buf;
-    msg.msg_controllen = sizeof(buf);
+
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_control = &cmsgbuf.buf;
+    msg.msg_controllen = sizeof(cmsgbuf.buf);
     msg.msg_iov = &dummy_iov;
     msg.msg_iovlen = 1;
+
     cmsg = CMSG_FIRSTHDR(&msg);
     cmsg->cmsg_level = SOL_SOCKET;
     cmsg->cmsg_type = SCM_RIGHTS;
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index d67cada..153ddcd 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -4741,7 +4741,13 @@
     if (!PyArg_ParseTuple(args, _Py_PARSE_PID "iO&:sched_setscheduler",
                           &pid, &policy, &convert_sched_param, &param))
         return NULL;
-    if (sched_setscheduler(pid, policy, &param))
+
+    /*
+    ** sched_setscheduler() returns 0 in Linux, but the previous
+    ** scheduling policy under Solaris/Illumos, and others.
+    ** On error, -1 is returned in all Operating Systems.
+    */
+    if (sched_setscheduler(pid, policy, &param) == -1)
         return posix_error();
     Py_RETURN_NONE;
 }
@@ -11301,12 +11307,12 @@
 #endif
 
 #ifdef HAVE_SCHED_H
+    if (ins(d, "SCHED_OTHER", (long)SCHED_OTHER)) return -1;
     if (ins(d, "SCHED_FIFO", (long)SCHED_FIFO)) return -1;
     if (ins(d, "SCHED_RR", (long)SCHED_RR)) return -1;
 #ifdef SCHED_SPORADIC
     if (ins(d, "SCHED_SPORADIC", (long)SCHED_SPORADIC) return -1;
 #endif
-    if (ins(d, "SCHED_OTHER", (long)SCHED_OTHER)) return -1;
 #ifdef SCHED_BATCH
     if (ins(d, "SCHED_BATCH", (long)SCHED_BATCH)) return -1;
 #endif
@@ -11316,6 +11322,18 @@
 #ifdef SCHED_RESET_ON_FORK
     if (ins(d, "SCHED_RESET_ON_FORK", (long)SCHED_RESET_ON_FORK)) return -1;
 #endif
+#ifdef SCHED_SYS
+    if (ins(d, "SCHED_SYS", (long)SCHED_SYS)) return -1;
+#endif
+#ifdef SCHED_IA
+    if (ins(d, "SCHED_IA", (long)SCHED_IA)) return -1;
+#endif
+#ifdef SCHED_FSS
+    if (ins(d, "SCHED_FSS", (long)SCHED_FSS)) return -1;
+#endif
+#ifdef SCHED_FX
+    if (ins(d, "SCHED_FX", (long)SCHED_FSS)) return -1;
+#endif
 #endif
 
 #ifdef HAVE_ATTR_XATTR_H
diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c
index f1f84e3..a6da056 100644
--- a/Modules/zlibmodule.c
+++ b/Modules/zlibmodule.c
@@ -1169,6 +1169,10 @@
     if (ver != NULL)
         PyModule_AddObject(m, "ZLIB_VERSION", ver);
 
+    ver = PyUnicode_FromString(zlibVersion());
+    if (ver != NULL)
+        PyModule_AddObject(m, "ZLIB_RUNTIME_VERSION", ver);
+
     PyModule_AddStringConstant(m, "__version__", "1.0");
 
     return m;
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 8f6f18f..5a4259d 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -525,8 +525,8 @@
     return x;
 }
 
-/* Get a C unsigned long int from a long int object.
-   Returns -1 and sets an error condition if overflow occurs. */
+/* Get a C size_t from a long int object. Returns (size_t)-1 and sets
+   an error condition if overflow occurs. */
 
 size_t
 PyLong_AsSize_t(PyObject *vv)
@@ -562,7 +562,7 @@
         if ((x >> PyLong_SHIFT) != prev) {
             PyErr_SetString(PyExc_OverflowError,
                 "Python int too large to convert to C size_t");
-            return (unsigned long) -1;
+            return (size_t) -1;
         }
     }
     return x;