static void rc_gsicc_link_cache_free(gs_memory_t * mem, void *ptr_in, client_name_t cname) { /* Ending the entire cache. The ref counts on all the links should be 0 */ gsicc_link_cache_t *link_cache = (gsicc_link_cache_t * ) ptr_in; while (link_cache->head != NULL) { gsicc_remove_link(link_cache->head, mem); link_cache->num_links--; } #ifdef DEBUG if (link_cache->num_links != 0) { eprintf1("num_links is %d, should be 0.\n", link_cache->num_links); } #endif gs_free_object(mem->stable_memory, link_cache->lock, "rc_gsicc_link_cache_free(lock)"); gs_free_object(mem->stable_memory, link_cache->wait, "rc_gsicc_link_cache_free(wait)"); gs_free_object(mem->stable_memory, link_cache, "rc_gsicc_link_cache_free"); }
static void rc_gsicc_link_cache_free(gs_memory_t * mem, void *ptr_in, client_name_t cname) { /* Ending the entire cache. The ref counts on all the links should be 0 */ gsicc_link_cache_t *link_cache = (gsicc_link_cache_t * ) ptr_in; while (link_cache->head != NULL) { gsicc_remove_link(link_cache->head, mem); link_cache->num_links--; } #ifdef DEBUG if (link_cache->num_links != 0) { eprintf1("num_links is %d, should be 0.\n", link_cache->num_links); } #endif gx_semaphore_free(link_cache->wait); link_cache->wait = NULL; gx_monitor_free(link_cache->lock); link_cache->lock = NULL; if_debug2(gs_debug_flag_icc,"[icc] Removing link cache = 0x%x memory = 0x%x\n", link_cache, link_cache->memory); gs_free_object(mem->stable_memory, link_cache, "rc_gsicc_link_cache_free"); }
gsicc_link_t* gsicc_get_link_profile(gs_imager_state *pis, gx_device *dev, cmm_profile_t *gs_input_profile, cmm_profile_t *gs_output_profile, gsicc_rendering_param_t *rendering_params, gs_memory_t *memory, bool include_softproof) { gsicc_hashlink_t hash; gsicc_link_t *link, *found_link; gcmmhlink_t link_handle = NULL; void **contextptr = NULL; gsicc_manager_t *icc_manager = pis->icc_manager; gsicc_link_cache_t *icc_link_cache = pis->icc_link_cache; gs_memory_t *cache_mem = pis->icc_link_cache->memory; gcmmhprofile_t *cms_input_profile; gcmmhprofile_t *cms_output_profile; /* First compute the hash code for the incoming case */ /* If the output color space is NULL we will use the device profile for the output color space */ gsicc_compute_linkhash(icc_manager, dev, gs_input_profile, gs_output_profile, rendering_params, &hash); /* Check the cache for a hit. Need to check if softproofing was used */ found_link = gsicc_findcachelink(hash, icc_link_cache, include_softproof); /* Got a hit, return link (ref_count for the link was already bumped */ if (found_link != NULL) return(found_link); /* TO FIX: We are really not going to want to have the members of this object visible outside gsiccmange */ /* If not, then lets create a new one if there is room or return NULL */ /* Caller will need to try later */ /* First see if we can add a link */ /* TODO: this should be based on memory usage, not just num_links */ gx_monitor_enter(icc_link_cache->lock); while (icc_link_cache->num_links >= ICC_CACHE_MAXLINKS) { /* If not, see if there is anything we can remove from cache. */ while ((link = gsicc_find_zeroref_cache(icc_link_cache)) == NULL) { icc_link_cache->num_waiting++; /* safe to unlock since above will make sure semaphore is signalled */ gx_monitor_leave(icc_link_cache->lock); /* we get signalled (released from wait) when a link goes to zero ref */ gx_semaphore_wait(icc_link_cache->wait); /* repeat the findcachelink to see if some other thread has */ /*already started building the link we need */ found_link = gsicc_findcachelink(hash, icc_link_cache, include_softproof); /* Got a hit, return link (ref_count for the link was already bumped */ if (found_link != NULL) return(found_link); /* TO FIX: We are really not going to want to have the members of this object visible outside gsiccmange */ gx_monitor_enter(icc_link_cache->lock); /* restore the lock */ /* we will re-test the num_links above while locked to insure */ /* that some other thread didn't grab the slot and max us out */ } /* Remove the zero ref_count link profile we found. */ /* Even if we remove this link, we may still be maxed out so */ /* the outermost 'while' will check to make sure some other */ /* thread did not grab the one we remove. */ gsicc_remove_link(link, cache_mem); icc_link_cache->num_links--; } /* insert an empty link that we will reserve so we */ /* can unlock while building the link contents */ link = gsicc_alloc_link(cache_mem->stable_memory, hash); link->icc_link_cache = icc_link_cache; link->next = icc_link_cache->head; icc_link_cache->head = link; icc_link_cache->num_links++; gx_monitor_leave(icc_link_cache->lock); /* now that we own this link we can release */ /* the lock since it is not valid */ /* Now compute the link contents */ cms_input_profile = gs_input_profile->profile_handle; if (cms_input_profile == NULL) { if (gs_input_profile->buffer != NULL) { cms_input_profile = gsicc_get_profile_handle_buffer(gs_input_profile->buffer, gs_input_profile->buffer_size); gs_input_profile->profile_handle = cms_input_profile; } else { /* See if we have a clist device pointer. */ if ( gs_input_profile->dev != NULL ) { /* ICC profile should be in clist. This is the first call to it. Note that the profiles are not really shared amongst threads like the links are. Hence the memory is for the local thread's chunk */ cms_input_profile = gsicc_get_profile_handle_clist(gs_input_profile, gs_input_profile->memory); gs_input_profile->profile_handle = cms_input_profile; } else { /* Cant create the link. No profile present, nor any defaults to use for this. Really need to throw an error for this case. */ gsicc_remove_link(link, cache_mem); icc_link_cache->num_links--; return(NULL); } } } cms_output_profile = gs_output_profile->profile_handle; if (cms_output_profile == NULL) { if (gs_output_profile->buffer != NULL) { cms_input_profile = gsicc_get_profile_handle_buffer(gs_input_profile->buffer, gs_input_profile->buffer_size); gs_output_profile->profile_handle = cms_output_profile; } else { /* See if we have a clist device pointer. */ if ( gs_output_profile->dev != NULL ) { /* ICC profile should be in clist. This is the first call to it. */ cms_output_profile = gsicc_get_profile_handle_clist(gs_output_profile, gs_output_profile->memory); gs_output_profile->profile_handle = cms_output_profile; } else { /* Cant create the link. No profile present, nor any defaults to use for this. Really need to throw an error for this case. */ gsicc_remove_link(link, cache_mem); icc_link_cache->num_links--; return(NULL); } } } link_handle = gscms_get_link(cms_input_profile, cms_output_profile, rendering_params); if (link_handle != NULL) { gsicc_set_link_data(link, link_handle, contextptr, hash, icc_link_cache->lock); } else { gsicc_remove_link(link, cache_mem); icc_link_cache->num_links--; return(NULL); } return(link); }