/* This is also exported for teardown after background printing */ void teardown_device_and_mem_for_thread(gx_device *dev, gp_thread_id thread_id, bool bg_print) { gx_device_clist_common *thread_cdev = (gx_device_clist_common *)dev; gx_device_clist_reader *thread_crdev = (gx_device_clist_reader *)dev; gs_memory_t *thread_memory = dev->memory; /* First finish the thread */ gp_thread_finish(thread_id); if (bg_print) { /* we are cleaning up a background printing thread, so we clean up similarly to */ /* what is done by clist_finish_page, but without re-opening the clist files. */ clist_teardown_render_threads(dev); /* we may have used multiple threads */ /* free the thread's icc_table since this was not done by clist_finish_page */ clist_free_icc_table(thread_crdev->icc_table, thread_memory); thread_crdev->icc_table = NULL; /* NB: gdev_prn_free_memory below will free the color_usage_array */ } else { /* make sure this doesn't get freed by gdev_prn_free_memory below */ ((gx_device_clist_reader *)thread_cdev)->color_usage_array = NULL; } rc_decrement(thread_crdev->icc_cache_cl, "teardown_render_thread"); thread_crdev->icc_cache_cl = NULL; /* * Free the BufferSpace, close the band files, optionally unlinking them. * We unlink the files if this call is cleaning up from bg printing. * Note that the BufferSpace is freed using 'ppdev->buf' so the 'data' * pointer doesn't need to be the one that the thread started with */ /* If this thread was being used for background printing and NumRenderingThreads > 0 */ /* the clist_setup_render_threads may have already closed these files */ if (thread_cdev->page_info.cfile != NULL) thread_cdev->page_info.io_procs->fclose(thread_cdev->page_info.bfile, thread_cdev->page_info.bfname, bg_print); if (thread_cdev->page_info.bfile != NULL) thread_cdev->page_info.io_procs->fclose(thread_cdev->page_info.cfile, thread_cdev->page_info.cfname, bg_print); thread_cdev->do_not_open_or_close_bandfiles = true; /* we already closed the files */ gdev_prn_free_memory((gx_device *)thread_cdev); /* Free the device copy this thread used. Note that the deviceN stuff if was allocated and copied earlier for the device will be freed with this call and the icc_struct ref count will be decremented. */ gs_free_object(thread_memory, thread_cdev, "clist_teardown_render_threads"); #ifdef DEBUG dmprintf(thread_memory, "rendering thread ending memory state...\n"); gs_memory_chunk_dump_memory(thread_memory); dmprintf(thread_memory, " memory dump done.\n"); #endif gs_memory_chunk_release(thread_memory); }
static int clist_process_page_mt(gx_device *dev, gx_process_page_options_t *options) { gx_device_printer *pdev = (gx_device_printer *)dev; gx_device_clist *cldev = (gx_device_clist *)dev; gx_device_clist_reader *crdev = &cldev->reader; int band_height = crdev->page_info.band_params.BandHeight; int band; int num_bands = (dev->height + band_height-1)/band_height; int code; int reverse = !!(options->options & GX_PROCPAGE_BOTTOM_UP); /* This page might not want multiple threads */ /* Also we don't support plane extraction using multiple threads */ if (pdev->num_render_threads_requested < 1) return clist_process_page(dev, options); if ((code = clist_close_writer_and_init_reader(cldev)) < 0) return code; /* can't recover from this */ /* Haven't done any rendering yet, try to set up the threads */ if (clist_setup_render_threads(dev, reverse ? dev->height-1 : 0, options) < 0) /* problem setting up the threads, revert to single threaded */ return clist_process_page(dev, options); if (reverse) { for (band = num_bands-1; band > 0; band--) { code = clist_get_band_from_thread(dev, band, options); if (code < 0) goto free_thread_out; } } else { for (band = 0; band < num_bands; band++) { code = clist_get_band_from_thread(dev, band, options); if (code < 0) goto free_thread_out; } } /* Always free up thread stuff before exiting*/ free_thread_out: clist_teardown_render_threads(dev); return code; }
/* rendering adjacent to the first band (forward or backward) */ static int clist_get_bits_rect_mt(gx_device *dev, const gs_int_rect * prect, gs_get_bits_params_t *params, gs_int_rect **unread) { gx_device_printer *pdev = (gx_device_printer *)dev; gx_device_clist *cldev = (gx_device_clist *)dev; gx_device_clist_common *cdev = (gx_device_clist_common *)dev; gx_device_clist_reader *crdev = &cldev->reader; gs_memory_t *mem = cdev->bandlist_memory; gs_get_bits_options_t options = params->options; int y = prect->p.y; int end_y = prect->q.y; int line_count = end_y - y; int band_height = crdev->page_info.band_params.BandHeight; int band = y / band_height; gs_int_rect band_rect; int lines_rasterized; gx_device *bdev; byte *mdata; uint raster = bitmap_raster(dev->width * dev->color_info.depth); int my; int code = 0; /* This page might not want multiple threads */ /* Also we don't support plane extraction using multiple threads */ if (pdev->num_render_threads_requested < 1 || (options & GB_SELECT_PLANES)) return clist_get_bits_rectangle(dev, prect, params, unread); if (prect->p.x < 0 || prect->q.x > dev->width || y < 0 || end_y > dev->height ) return_error(gs_error_rangecheck); if (line_count <= 0 || prect->p.x >= prect->q.x) return 0; if (crdev->ymin < 0) { if ((code = clist_close_writer_and_init_reader(cldev)) < 0) return code; if (clist_setup_render_threads(dev, y) < 0) /* problem setting up the threads, revert to single threaded */ return clist_get_bits_rectangle(dev, prect, params, unread); } else { if (crdev->render_threads == NULL) { /* If we get here with with ymin >=0, it's because we closed the threads */ /* while doing a page due to an error. Use single threaded mode. */ return clist_get_bits_rectangle(dev, prect, params, unread); } } /* If we already have the band's data, just return it */ if (y < crdev->ymin || end_y > crdev->ymax) code = clist_get_band_from_thread(dev, band); if (code < 0) goto free_thread_out; mdata = crdev->data + crdev->page_tile_cache_size; if ((code = gdev_create_buf_device(cdev->buf_procs.create_buf_device, &bdev, cdev->target, y, NULL, mem, clist_get_band_complexity(dev,y))) < 0 || (code = crdev->buf_procs.setup_buf_device(bdev, mdata, raster, NULL, y - crdev->ymin, line_count, crdev->ymax - crdev->ymin)) < 0) goto free_thread_out; lines_rasterized = min(band_height, line_count); /* Return as much of the rectangle as falls within the rasterized lines. */ band_rect = *prect; band_rect.p.y = 0; band_rect.q.y = lines_rasterized; code = dev_proc(bdev, get_bits_rectangle) (bdev, &band_rect, params, unread); cdev->buf_procs.destroy_buf_device(bdev); if (code < 0) goto free_thread_out; /* Note that if called via 'get_bits', the line count will always be 1 */ if (lines_rasterized == line_count) { return code; } /***** TODO: Handle the below with data from the threads *****/ /* * We'll have to return the rectangle in pieces. Force GB_RETURN_COPY * rather than GB_RETURN_POINTER, and require all subsequent pieces to * use the same values as the first piece for all of the other format * options. If copying isn't allowed, or if there are any unread * rectangles, punt. */ if (!(options & GB_RETURN_COPY) || code > 0) return gx_default_get_bits_rectangle(dev, prect, params, unread); options = params->options; if (!(options & GB_RETURN_COPY)) { /* Redo the first piece with copying. */ params->options = options = (params->options & ~GB_RETURN_ALL) | GB_RETURN_COPY; lines_rasterized = 0; } { gs_get_bits_params_t band_params; uint raster = gx_device_raster(bdev, true); code = gdev_create_buf_device(cdev->buf_procs.create_buf_device, &bdev, cdev->target, y, NULL, mem, clist_get_band_complexity(dev, y)); if (code < 0) return code; band_params = *params; while ((y += lines_rasterized) < end_y) { /* Increment data pointer by lines_rasterized. */ if (band_params.data) band_params.data[0] += raster * lines_rasterized; line_count = end_y - y; code = clist_rasterize_lines(dev, y, line_count, bdev, NULL, &my); if (code < 0) break; lines_rasterized = min(code, line_count); band_rect.p.y = my; band_rect.q.y = my + lines_rasterized; code = dev_proc(bdev, get_bits_rectangle) (bdev, &band_rect, &band_params, unread); if (code < 0) break; params->options = options = band_params.options; if (lines_rasterized == line_count) break; } cdev->buf_procs.destroy_buf_device(bdev); } return code; /* Free up thread stuff */ free_thread_out: clist_teardown_render_threads(dev); return code; }