1 /*
2  * cue-cache.cc
3  * Copyright 2016 John Lindgren
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions, and the following disclaimer in the documentation
13  *    provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 #include "cue-cache.h"
21 #include "multihash.h"
22 #include "playlist-internal.h"
23 #include "threads.h"
24 
25 enum NodeState
26 {
27     NotLoaded,
28     Loading,
29     Loaded
30 };
31 
32 struct CueCacheNode
33 {
34     Index<PlaylistAddItem> items;
35     NodeState state = NotLoaded;
36     int refcount = 0;
37 };
38 
39 static SimpleHash<String, CueCacheNode> cache;
40 static aud::mutex mutex;
41 static aud::condvar cond;
42 
CueCacheRef(const char * filename)43 CueCacheRef::CueCacheRef(const char * filename) : m_filename(filename)
44 {
45     auto mh = mutex.take();
46 
47     m_node = cache.lookup(m_filename);
48     if (!m_node)
49         m_node = cache.add(m_filename, CueCacheNode());
50 
51     m_node->refcount++;
52 }
53 
~CueCacheRef()54 CueCacheRef::~CueCacheRef()
55 {
56     auto mh = mutex.take();
57 
58     m_node->refcount--;
59     if (!m_node->refcount)
60         cache.remove(m_filename);
61 }
62 
load()63 const Index<PlaylistAddItem> & CueCacheRef::load()
64 {
65     auto mh = mutex.take();
66     String title; // not used
67 
68     switch (m_node->state)
69     {
70     case NotLoaded:
71         // load the cuesheet in this thread
72         m_node->state = Loading;
73         mh.unlock();
74         playlist_load(m_filename, title, m_node->items);
75         mh.lock();
76 
77         m_node->state = Loaded;
78         cond.notify_all();
79         break;
80 
81     case Loading:
82         // wait for cuesheet to load in another thread
83         while (m_node->state != Loaded)
84             cond.wait(mh);
85 
86         break;
87 
88     case Loaded:
89         // cuesheet already loaded
90         break;
91     }
92 
93     return m_node->items;
94 }
95