source: tags/arb_5.3/ptpan/PT_cachehandler.cxx

Last change on this file was 5908, checked in by westram, 15 years ago
  • source files with identical names are really a pain when using valgrind
File size: 6.1 KB
Line 
1#include <stdio.h>
2// #include <malloc.h>
3#include <stdlib.h>
4#include <string.h>
5#include <PT_server.h>
6#include <PT_server_prototypes.h>
7#include "ptpan.h"
8#include "pt_prototypes.h"
9
10/* /// "AllocCacheHandler()" */
11struct CacheHandler * AllocCacheHandler(void)
12{
13  struct CacheHandler *ch;
14  ch = (struct CacheHandler *) calloc(sizeof(struct CacheHandler), 1);
15  if(!ch)
16  {
17    return(NULL); /* out of memory */
18  }
19  /* freshly initialize a cache handler */
20  NewList(&ch->ch_UsedNodes);
21  NewList(&ch->ch_FreeNodes);
22  return(ch);
23}
24/* \\\ */
25
26/* /// "FreeCacheHandler()" */
27void FreeCacheHandler(struct CacheHandler *ch)
28{
29  struct CacheNode *cn;
30
31  /* NOTE: Does NOT flush the cache! */
32  /* free memory in used node cache */
33  cn = (struct CacheNode *) ch->ch_UsedNodes.lh_Head;
34  while(cn->cn_Node.ln_Succ)
35  {
36    Remove(&cn->cn_Node);
37    freeset(cn, (struct CacheNode *) ch->ch_UsedNodes.lh_Head);
38  }
39  /* free memory in free node cache */
40  cn = (struct CacheNode *) ch->ch_FreeNodes.lh_Head;
41  while(cn->cn_Node.ln_Succ)
42  {
43    Remove(&cn->cn_Node);
44    freeset(cn, (struct CacheNode *) ch->ch_FreeNodes.lh_Head);
45  }
46  /* free structure itself */
47  free(ch);
48}
49/* \\\ */
50
51/* /// "CacheLoadData()" */
52struct CacheNode * CacheLoadData(struct CacheHandler *ch,
53 struct CacheNode *cn, APTR ud)
54{
55  struct CacheNode *firstcn;
56  struct CacheNode *secondcn;
57  ULONG memused;
58
59  if(ch->ch_CacheDisabled && ch->ch_LastNode)
60  {
61    /* unload last node, if cache was disabled */
62    CacheUnloadData(ch, ch->ch_LastNode);
63    ch->ch_LastNode = NULL;
64  }
65
66  /* allocate CacheNode, if not allocated already */
67  if(!cn)
68  {
69    cn = (struct CacheNode *) calloc(sizeof(struct CacheNode), 1);
70    if(!cn)
71    {
72      return(NULL);
73    }
74  } else {
75    Remove(&cn->cn_Node); /* unlink first */
76  }
77
78  /* only fill in user data, if given, preventing overwrite */
79  if(ud)
80  {
81    cn->cn_UserData = ud;
82  }
83  cn->cn_Node.ln_Pri++; /* how often was this thing used? */
84  cn->cn_LastUseID = ++ch->ch_AccessID; /* set last access */
85
86  if(cn->cn_Loaded) /* check if already loaded */
87  {
88    AddTail(&ch->ch_UsedNodes, &cn->cn_Node); /* move to the end of the list */
89    return(cn); /* no need to load, we're done */
90  }
91
92  /* do we need to unload some bits? */
93  memused = (*ch->ch_SizeFunc)(ch, cn->cn_UserData);
94  while((ch->ch_MemUsage + memused > ch->ch_MaxCapacity) &&
95    (ch->ch_UsedNodes.lh_Head->ln_Succ) &&
96    (!ch->ch_CacheDisabled))
97  {
98    /* capacity exhausted, must unload */
99    ULONG remmemused;
100    firstcn = (struct CacheNode *) ch->ch_UsedNodes.lh_Head;
101    secondcn = (struct CacheNode *) firstcn->cn_Node.ln_Succ;
102    if(secondcn->cn_Node.ln_Succ) /* there are at least two nodes, check which one to kill */
103    {
104      if(firstcn->cn_Node.ln_Pri > secondcn->cn_Node.ln_Pri)
105      {
106    //printf("Second");
107    firstcn = secondcn; /* the second one loses */
108      } else {
109    //printf("First");
110      }
111    } else {
112      //printf("Only");
113    }
114    Remove(&firstcn->cn_Node); /* unlink anyway */
115
116    /* get size of data */
117    remmemused = (*ch->ch_SizeFunc)(ch, firstcn->cn_UserData);
118    if((*ch->ch_UnloadFunc)(ch, firstcn->cn_UserData))
119    {
120      /* data unloaded successfully */
121      //printf(" unloaded!\n");
122      ch->ch_SwapCount++;
123      ch->ch_MemUsage -= remmemused;
124      /* move the node to the unused list */
125      AddTail(&ch->ch_FreeNodes, &firstcn->cn_Node);
126      firstcn->cn_Loaded = FALSE;
127    } else {
128      /* unload failed, move node to the end of the queue */
129      //printf(" unload failed!\n");
130      AddTail(&ch->ch_UsedNodes, &firstcn->cn_Node);
131      /* avoid infinite loop */
132      if(!secondcn)
133      {
134    //printf("Bailing out!\n");
135    break;
136      }
137    }
138  }
139
140  /* now load the data */
141  if((*ch->ch_LoadFunc)(ch, cn->cn_UserData))
142  {
143    /* loading successful */
144    ch->ch_MemUsage += memused;
145    //printf("Successfully loaded (%ld/%ld)\n", memused, ch->ch_MemUsage);
146    cn->cn_Loaded = TRUE;
147    AddTail(&ch->ch_UsedNodes, &cn->cn_Node);
148    if(ch->ch_CacheDisabled)
149    {
150      ch->ch_LastNode = cn;
151    }
152    return(cn); /* no need to load, we're done */
153  } else {
154    /* loading failed */
155    //printf("Loading failed (%ld)\n", memused);
156    AddTail(&ch->ch_FreeNodes, &cn->cn_Node);
157    return(cn);
158  }
159}
160/* \\\ */
161
162/* /// "CacheMemUsage()" */
163ULONG CacheMemUsage(struct CacheHandler *ch)
164{
165  return(ch->ch_MemUsage);
166}
167/* \\\ */
168
169/* /// "DisableCache()" */
170void DisableCache(struct CacheHandler *ch)
171{
172  ch->ch_CacheDisabled = TRUE;
173}
174/* \\\ */
175
176/* /// "DisableCache()" */
177void EnableCache(struct CacheHandler *ch)
178{
179  ch->ch_CacheDisabled = FALSE;
180}
181/* \\\ */
182
183/* /// "CacheDataLoaded()" */
184BOOL CacheDataLoaded(struct CacheNode *cn)
185{
186  /* if cn == NULL, it's not loaded for sure */
187  if(!cn)
188  {
189    return(FALSE);
190  }
191  return(cn->cn_Loaded);
192}
193/* \\\ */
194
195/* /// "FreeCacheNode()" */
196void FreeCacheNode(struct CacheHandler *ch, struct CacheNode *cn)
197{
198  if(!cn)
199  {
200    return; /* ignore null pointers */
201  }
202  if(cn->cn_Loaded) /* unload data first */
203  {
204    CacheUnloadData(ch, cn);
205  }
206  /* remove from list */
207  Remove(&cn->cn_Node);
208  free(cn);
209}
210/* \\\ */
211
212/* /// "CacheUnloadData()" */
213BOOL CacheUnloadData(struct CacheHandler *ch, struct CacheNode *cn)
214{
215  ULONG memused;
216
217  if(!cn)
218  {
219    return(FALSE); /* null pointer */
220  }
221  if(!cn->cn_Loaded)
222  {
223    return(FALSE); /* not loaded */
224  }
225
226  /* try to unload the data */
227  memused = (*ch->ch_SizeFunc)(ch, cn->cn_UserData);
228  if((*ch->ch_UnloadFunc)(ch, cn->cn_UserData))
229  {
230    //printf("Unloaded %ld\n", memused);
231    ch->ch_MemUsage -= memused; /* we actually unloaded the data */
232    /* move the node to the unused list */
233    Remove(&cn->cn_Node);
234    AddTail(&ch->ch_FreeNodes, &cn->cn_Node);
235    cn->cn_Loaded = FALSE;
236  }
237  return(TRUE);
238}
239/* \\\ */
240
241/* /// "FlushCache()" */
242ULONG FlushCache(struct CacheHandler *ch)
243{
244  struct CacheNode *cn;
245  struct CacheNode *nextcn;
246  ULONG oldmemused = ch->ch_MemUsage;
247
248  /* traverse nodes and call UnloadFunc for each of them */
249  cn = (struct CacheNode *) ch->ch_UsedNodes.lh_Head;
250  while(cn->cn_Node.ln_Succ)
251  {
252    nextcn = (struct CacheNode *) cn->cn_Node.ln_Succ;
253    CacheUnloadData(ch, cn);
254    cn = nextcn;
255  }
256  return(oldmemused - ch->ch_MemUsage);
257}
258/* \\\ */
Note: See TracBrowser for help on using the repository browser.