+#ifdef __osf__
+
+/* thread for calling back to a compressor's memory allocator
+ * Needed for Digital UNIX since it's VM can't handle requests
+ * for large amounts of memory without blocking. The thread
+ * provides a context in which we can call a memory allocator
+ * that may block.
+ */
+static void
+ppp_comp_alloc(comp_state_t *cp)
+{
+ unsigned char *opt_data;
+ int len, cmd;
+ struct compressor *comp;
+ thread_t thread;
+
+#if (MAJOR_VERSION <= 2)
+
+ /* In 2.x and earlier the argument gets passed
+ * in the thread structure itself. Yuck.
+ */
+ thread = current_thread();
+ cp = thread->reply_port;
+ thread->reply_port = PORT_NULL;
+
+#endif
+
+ for (;;) {
+ assert_wait((vm_offset_t)&cp->memreq.comp, TRUE);
+ thread_block();
+ opt_data = cp->memreq.comp;
+ len = cp->memreq.len;
+ cmd = cp->memreq.cmd;
+
+ if (cmd == PPPIO_XCOMP) {
+ comp = cp->xcomp;
+ cp->memreq.mem = (*comp->comp_alloc)(opt_data, len);
+ } else {
+ comp = cp->rcomp;
+ cp->memreq.mem = (*comp->decomp_alloc)(opt_data, len);
+ }
+ if (!cp->memreq.mem)
+ cp->memreq.ret = ENOSR;
+ else
+ bcopy(opt_data, cp->memreq.mem, len);
+
+ /* have to free thunk here, since there's
+ * no guarantee that the user will call the ioctl
+ * again if we've taken a long time to complete
+ */
+ FREE(opt_data, len);
+ cp->memreq.ret = 0;
+ }
+}
+
+#endif /* __osf__ */
+
+/* here's the deal with memory allocation under Digital UNIX.
+ * Some other may also benefit from this...
+ * We can't ask for huge chunks of memory in a context where
+ * the caller can't be put to sleep (like, here.) The alloc
+ * is likely to fail. Instead we do this: the first time we
+ * get called, kick off a thread to do the allocation. Return
+ * immediately to the caller with EAGAIN, as an indication that
+ * they should send down the ioctl again. By the time the
+ * second call comes in it's likely that the memory allocation
+ * thread will have returned with the requested memory. We will
+ * continue to return EAGAIN however until the thread has completed.
+ * When it has, we return zero (and the memory) if the allocator
+ * was successful and ENOSR otherwise.
+ *
+ * Callers of the RCOMP and XCOMP ioctls are encouraged (but not
+ * required) to loop for some number of iterations with a small
+ * delay in the loop body (for instance a 1/10-th second "sleep"
+ * via select.)
+ */