1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
|
#ifndef STOCK_DATABASE_TPP
#define STOCK_DATABASE_TPP
// local headers
#include "Stock_Database.h"
// ACE headers
#include <ace/OS_NS_unistd.h>
#include <ace/UUID.h>
#include <fstream>
#include <vector>
template <typename CALLBACK>
struct Map_Init
{
Map_Init (typename Stock_Database<CALLBACK>::Stock_Map &map)
: map_ (map)
{
}
void operator () (const typename Stock_Database<CALLBACK>::Init_Map::value_type &item)
{
typename Stock_Database<CALLBACK>::StockInfo stock_info (item.first.c_str ());
// If the initial value is nonzero, use that - otherwise, use a number
// between 0 and 100
stock_info.low_ =
stock_info.last_ =
stock_info.high_ = item.second ? item.second : ACE_OS::rand () % 100;
map_[item.first] = stock_info;
}
typename Stock_Database<CALLBACK>::Stock_Map &map_;
};
// Stock_Database
template <typename CALLBACK>
Stock_Database<CALLBACK>::Stock_Database (u_int rate)
: rate_ (rate),
active_ (false)
{
Init_Map map;
map["IBM"] = 0;
map["MSFT"] = 0;
map["INTEL"] = 0;
std::for_each (map.begin (),
map.end (),
Map_Init<CALLBACK> (this->stock_map_));
}
template <typename CALLBACK>
Stock_Database<CALLBACK>::Stock_Database (const char *file, u_int rate)
: filename_ (file),
rate_ (rate),
active_ (false)
{
this->handle_signal (0, 0, 0);
}
template <typename CALLBACK>
Stock_Database<CALLBACK>::Stock_Database (const Init_Map &stockmap,
u_int rate)
: rate_ (rate),
active_ (false)
{
std::for_each (stockmap.begin (),
stockmap.end (),
Map_Init<CALLBACK> (this->stock_map_));
}
// get_stock_info
template <typename CALLBACK>
typename Stock_Database<CALLBACK>::StockInfo
Stock_Database<CALLBACK>::get_stock_info(const char *name)
{
ACE_READ_GUARD_RETURN (ACE_RW_Thread_Mutex,
guard,
this->lock_,
StockInfo ("Error"));
// Locate the <stock_name> in the database.
ACE_DEBUG ((LM_DEBUG,
"*** message: searching the stock_map_ for the stock_name\n"));
typename Stock_Map::iterator iter = this->stock_map_.find (std::string (name));
if (iter == this->stock_map_.end ())
throw Invalid_Stock ();
ACE_DEBUG ((LM_DEBUG, "*** message: returning stock_info to the client\n"));
return iter->second;
}
template <typename CALLBACK>
typename Stock_Database<CALLBACK>::Cookie
Stock_Database<CALLBACK>::register_callback (CALLBACK &obj)
{
ACE_Utils::UUID uuid;
ACE_Utils::UUID_GENERATOR::instance ()->generate_UUID (uuid);
this->callbacks_[uuid.to_string ()->c_str ()] = &obj;
return uuid.to_string ()->c_str ();
}
template <typename CALLBACK>
void
Stock_Database<CALLBACK>::update_rate (u_int rate)
{
this->rate_ = rate;
}
template <typename CALLBACK>
void
Stock_Database<CALLBACK>::start (void)
{
if (!this->active_)
{ // Double checked locking
ACE_WRITE_GUARD (ACE_RW_Thread_Mutex,
guard,
this->lock_);
if (!this->active_)
{
this->active_ = true;
this->activate (THR_NEW_LWP | THR_JOINABLE, 1);
}
}
}
template <typename CALLBACK>
void
Stock_Database<CALLBACK>::stop (void)
{
ACE_WRITE_GUARD (ACE_RW_Thread_Mutex,
guard,
this->lock_);
this->active_ = false;
}
template <typename CALLBACK>
int
Stock_Database<CALLBACK>::handle_signal (int,
siginfo_t *,
ucontext_t *)
{
ACE_WRITE_GUARD_RETURN (ACE_RW_Thread_Mutex,
guard,
this->lock_,
-1);
std::ifstream input (this->filename_.c_str ());
std::string name;
u_int value = 0;
typename Stock_Database<CALLBACK>::Init_Map map;
while (input.good ())
{
input >> name;
input >> value;
map[name] = value;
}
input.close ();
std::for_each (map.begin (),
map.end (),
Map_Init<CALLBACK> (this->stock_map_));
return 0;
}
template <typename CALLBACK>
struct Stock_Updater
{
void operator () (typename Stock_Database<CALLBACK>::Stock_Map::value_type &item)
{
// Determine if the stock has changed.
if (ACE_OS::rand () % 2)
return; // Nope! On to the next!
changed_.push_back (item.first);
// Determine the amount of change of the stock. We will
// only permit a 5 point change at a time in either direction
int delta = ACE_OS::rand () % 10 - 5;
// We don't want negative stock values!
if (item.second.last_ <= delta)
delta *= -1;
// Calculate the new values for the stock.
item.second.last_ += delta;
if (item.second.last_ < item.second.low_)
item.second.low_ = item.second.last_;
else if (item.second.last_ > item.second.high_)
item.second.high_ = item.second.last_;
}
void operator () (typename Stock_Database<CALLBACK>::Callback_Map::value_type &item)
{
(*item.second) (changed_);
}
private:
std::vector <std::string> changed_;
};
template <typename CALLBACK>
int
Stock_Database<CALLBACK>::svc (void)
{
ACE_DEBUG ((LM_DEBUG, "tock!\n"));
while (this->active_)
{
{
// Init our functor
Stock_Updater<CALLBACK> updater;
{ // Control the scope of our mutex to avoid deadlock.
ACE_WRITE_GUARD_RETURN (ACE_RW_Thread_Mutex,
guard,
this->lock_,
-1);
updater = std::for_each (this->stock_map_.begin (),
this->stock_map_.end (),
updater);
}
// Update stock prices
// notify callbacks
std::for_each (this->callbacks_.begin (),
this->callbacks_.end (),
updater);
}
// Sleep for one second.
ACE_OS::sleep (this->rate_);
}
return 0;
}
#endif /* STOCK_DATABASE_TPP */
|