Skip to main content
summaryrefslogblamecommitdiffstats
blob: 44a9e08535c507d80e84c67c7ade0929589c992a (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                                                
                                                                






                                                                           
                                                                          








                                                                                 
                       
                   
                   





                                     
 



                                   

                     



                      
                     
 

                                                           
                              

                                          
                       
 
                                    

              
                       
                      
                          
                                                   
                          
                                    
                              
     
                                                                                                    

                                                                                                                   
                                                                                       
                                                       

                       

 



                                                                                          
                                        








                                          
                       
                                 
                                          
                           
                                                      
                      

 
             
                                        


                                                                         
                                 
                               
                                                               
                                                            
                                                           
                                      
                                                                                                                                              
         





                                                                       




                                                                                

                                                                      
     




                                                                                     
                     


                              
                                          


                                        
                                 
                         
                              


                              
                                                                                                           


                                                                                  

                                          
                                                 

     

                               





                                           
                                        

                                     
 
/*******************************************************************************
 * Copyright (c) 2009, 2010 Wind River Systems, Inc. and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v1.0 which accompany this distribution.
 * The Eclipse Public License is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 * You may elect to redistribute this code under either of these licenses.
 *
 * Contributors:
 *     Wind River Systems - initial API and implementation
 *******************************************************************************/

/*
 * Abstract asynchronous data cache support.
 */

#include <tcf/config.h>
#include <assert.h>
#include <string.h>
#include <tcf/framework/errors.h>
#include <tcf/framework/exceptions.h>
#include <tcf/framework/myalloc.h>
#include <tcf/framework/events.h>
#include <tcf/framework/trace.h>
#include <tcf/framework/cache.h>

typedef struct WaitingCacheClient {
    CacheClient * client;
    Channel * channel;
    void * args;
    size_t args_size;
    int args_copy;
#ifndef NDEBUG
    const char * file;
    int line;
#endif
} WaitingCacheClient;

static WaitingCacheClient current_client = {0, 0, 0, 0, 0};
static int client_exited = 0;
static int cache_miss_cnt = 0;
static WaitingCacheClient * wait_list_buf;
static unsigned wait_list_max;
static LINK cache_list;

static void run_cache_client(void) {
    Trap trap;

    cache_miss_cnt = 0;
    client_exited = 0;
    if (set_trap(&trap)) {
        current_client.client(current_client.args);
        clear_trap(&trap);
        assert(cache_miss_cnt == 0);
        assert(client_exited);
    }
    else if (get_error_code(trap.error) != ERR_CACHE_MISS || client_exited || cache_miss_cnt == 0) {
        trace(LOG_ALWAYS, "Unhandled exception in data cache client: %d %s", trap.error, errno_to_str(trap.error));
    }
    if (cache_miss_cnt == 0 && current_client.args_copy) loc_free(current_client.args);
    memset(&current_client, 0, sizeof(current_client));
    cache_miss_cnt = 0;
    client_exited = 0;
}

void cache_enter(CacheClient * client, Channel * channel, void * args, size_t args_size) {
    assert(is_dispatch_thread());
    assert(client != NULL);
    assert(channel != NULL);
    assert(!is_channel_closed(channel));
    assert(current_client.client == NULL);
    current_client.client = client;
    current_client.channel = channel;
    current_client.args = args;
    current_client.args_size = args_size;
    current_client.args_copy = 0;
    run_cache_client();
}

void cache_exit(void) {
    assert(is_dispatch_thread());
    assert(current_client.client != NULL);
    assert(!client_exited);
    if (cache_miss_cnt > 0) exception(ERR_CACHE_MISS);
    client_exited = 1;
}

#ifdef NDEBUG
void cache_wait(AbstractCache * cache) {
#else
void cache_wait_dbg(const char * file, int line, AbstractCache * cache) {
#endif
    assert(is_dispatch_thread());
    assert(client_exited == 0);
    if (current_client.client != NULL && cache_miss_cnt == 0) {
        if (cache_list.next == NULL) list_init(&cache_list);
        if (cache->wait_list_cnt >= cache->wait_list_max) {
            cache->wait_list_max += 8;
            cache->wait_list_buf = (WaitingCacheClient *)loc_realloc(cache->wait_list_buf, cache->wait_list_max * sizeof(WaitingCacheClient));
        }
        if (current_client.args != NULL && !current_client.args_copy) {
            void * mem = loc_alloc(current_client.args_size);
            memcpy(mem, current_client.args, current_client.args_size);
            current_client.args = mem;
            current_client.args_copy = 1;
        }
#ifndef NDEBUG
        current_client.file = file;
        current_client.line = line;
#endif
        if (cache->wait_list_cnt == 0) list_add_last(&cache->link, &cache_list);
        cache->wait_list_buf[cache->wait_list_cnt++] = current_client;
        channel_lock(current_client.channel);
    }
#ifndef NDEBUG
    else if (current_client.client == NULL) {
        trace(LOG_ALWAYS, "cache_wait(): illegal cache access at %s:%d", file, line);
    }
#endif
    cache_miss_cnt++;
    exception(ERR_CACHE_MISS);
}

void cache_notify(AbstractCache * cache) {
    unsigned i;
    unsigned cnt = cache->wait_list_cnt;

    assert(is_dispatch_thread());
    if (cnt == 0) return;
    list_remove(&cache->link);
    cache->wait_list_cnt = 0;
    if (wait_list_max < cnt) {
        wait_list_max = cnt;
        wait_list_buf = (WaitingCacheClient *)loc_realloc(wait_list_buf, cnt * sizeof(WaitingCacheClient));
    }
    memcpy(wait_list_buf, cache->wait_list_buf, cnt * sizeof(WaitingCacheClient));
    for (i = 0; i < cnt; i++) {
        current_client = wait_list_buf[i];
        run_cache_client();
        channel_unlock(wait_list_buf[i].channel);
    }
}

Channel * cache_channel(void) {
    return current_client.channel;
}

void cache_dispose(AbstractCache * cache) {
    assert(is_dispatch_thread());
    assert(cache->wait_list_cnt == 0);
    assert(list_is_empty(&cache->link));
    loc_free(cache->wait_list_buf);
    memset(cache, 0, sizeof(*cache));
}

Back to the top