Statistics
| Branch: | Revision:

root / include / cownedobject.h @ ffa9279f

History | View | Annotate | Download (12 KB)

1 01873262 Georg Kunz
//==========================================================================
2
//  COWNEDOBJECT.H - part of
3
//                     OMNeT++/OMNEST
4
//            Discrete System Simulation in C++
5
//
6
//  Author: Andras Varga
7
//
8
//==========================================================================
9
10
/*--------------------------------------------------------------*
11
  Copyright (C) 1992-2008 Andras Varga
12
  Copyright (C) 2006-2008 OpenSim Ltd.
13

14
  This file is distributed WITHOUT ANY WARRANTY. See the file
15
  `license' for details on this and other legal matters.
16
*--------------------------------------------------------------*/
17
18
#ifndef __COWNEDOBJECT_H
19
#define __COWNEDOBJECT_H
20
21
#include <typeinfo>
22
#include <iostream>
23
#include "simkerneldefs.h"
24
#include "simutil.h"
25
#include "cnamedobject.h"
26
#include "cexception.h"
27
28
#ifdef ATOMIC_OPS_DEBUG
29
        #include "catomicopsdebug.h"
30
#else
31
        #include <atomic_ops.h>
32
#endif
33
34
NAMESPACE_BEGIN
35
36
37
class cOwnedObject;
38
class cStaticFlag;
39
class cSimulation;
40
class cDefaultList;
41
class cMessage;
42
class cPacket;
43
44
45
/**
46
 * Base class for several classes in the \opp library. Instances of
47
 * cOwnedObjects are kept track of by the simulation kernel, and
48
 * may be inserted into cQueue and cArray.
49
 *
50
 * It is not always a good idea to subclass your own classes from
51
 * cOwnedObject, especially if they are small data objects.
52
 * The more lightweight cObject is often a better choice.
53
 *
54
 * When subclassing cOwnedObject, some virtual member functions are
55
 * expected to be redefined: dup() are mandatory to be redefined, and
56
 * often you'll want to redefine info() and detailedInfo() as well.
57
 *
58
 * <b>Ownership management</b> helps \opp catch common programming
59
 * errors. As a definition, <i>ownership means the exclusive right and duty
60
 * to delete owned objects.</i>
61
 *
62
 * cOwnedObjects hold a pointer to their owner objects; the getOwner() method returns
63
 * this pointer. An example will help to understand how it is used:
64
 *
65
 *    - when you insert a cMessage into a cQueue, the cQueue will become
66
 *      the owner of the message, and will set the message's owner to itself.
67
 *
68
 *    - a message object can be at one place only at any given time.
69
 *      When you try to insert the same cMessage again into another (or the same)
70
 *      cQueue, you'll get an error message that it is already in a cQueue --
71
 *      sparing you a sure crash later.
72
 *
73
 *    - similarly, if you try to send the same message, you'll get an error
74
 *      message that it cannot be sent because it is still enqueued --
75
 *      another crash scenario eliminated. Like the previous one, this
76
 *      test is done by checking the owner pointer in cMessage.
77
 *
78
 *    - even if you try to delete the message while it is in the queue,
79
 *      you'll get an error message instead of just a crash. This is because
80
 *      cOwnedObject destructor asks for the owner's blessing -- but cQueue will
81
 *      protest by throwing an exception.
82
 *
83
 *    - when you remove the message from the cQueue, the cQueue will "release"
84
 *      the object; the current module will become the message's "soft" owner,
85
 *      changing the owner pointer in the message object.
86
 *
87
 *    - "soft" owner means that now you can send the message object or insert
88
 *      it into another cQueue -- the module as a soft owner will let it go.
89
 *
90
 *    - the same mechanism can ensure that when a self-message is currently
91
 *      scheduled (owner is the scheduled-events list) or sent to another module
92
 *      (owner is the other module) you cannot send or schedule it, or
93
 *      insert it into a queue. <i>In short: the ownership mechanism is good to your
94
 *      health.</i>
95
 *
96
 *    - when the queue is deleted, it also deletes all objects it contains.
97
 *      (The cQueue always owns all objects inserted into it -- no exception).
98
 *
99
 * The above ownership mechanisms are at work when any cOwnedObject-subclass object
100
 * gets inserted into any cOwnedObject-subclass container (cQueue, cArray).
101
 *
102
 * Some more details, in case you are writing a class that acts as a container:
103
 *
104
 *    - you should use the functions take(), drop() on inserting/removing objects
105
 *    - you should delete the owned objects in the destructor
106
 *    - the copy constructor of a container should dup() the owned objects
107
 *      and take() the copies
108
 *    - if you want to have a class which contains cOwnedObject-subclasses as
109
 *      data members: your class (the enclosing object) should own them --
110
 *      call take() from the constructor and drop() from the destructor.
111
 *
112
 * @ingroup SimCore
113
 */
114
class SIM_API cOwnedObject : public cNamedObject
115
{
116
    friend class cObject;
117
    friend class cDefaultList;
118
    friend class cSimulation;
119
    friend class cMessage;  // because of refcounting business
120
    friend class cPacket;   // because of refcounting business
121
122
  private:
123
    cObject *ownerp;   // owner pointer
124
    unsigned int pos;  // used only when owner is a cDefaultList
125
126
  private:
127
    // list in which objects are accumulated if there is no simple module in context
128
    // (see also setDefaultOwner() and cSimulation::setContextModule())
129
    static cDefaultList *defaultowner;
130
131
    // global variables for statistics
132
    static AO_t total_objs;
133
    static AO_t live_objs;
134
135
  public:
136
    // internal
137
    virtual void removeFromOwnershipTree();
138
139
    // internal
140
    static void setDefaultOwner(cDefaultList *list);
141
142
  public:
143
    /** @name Constructors, destructor, assignment. */
144
    //@{
145
    /**
146
     * Create object without a name. The object will be initially owned by
147
     * defaultOwer().
148
     */
149
    cOwnedObject();
150
151
    /**
152
     * Create object with given name. The object will be initially owned by
153
     * defaultOwer(). Name pooling is an optimization feature.
154
     */
155
    explicit cOwnedObject(const char *name, bool namepooling=true);
156
157
    /**
158
     * Copy constructor. In derived classes, it is usually implemented
159
     * as <tt>{operator=(obj);</tt>
160
     */
161
    cOwnedObject(const cOwnedObject& obj);
162
163
    /**
164
     * Destructor.
165
     */
166
    virtual ~cOwnedObject();
167
168
    /**
169
     * The assignment operator. Derived classes should contain similar
170
     * methods (<tt>cClassName& cClassName::operator=(cClassName&)</tt>).
171
     *
172
     * Assigment copies the contents of the object EXCEPT for the name string.
173
     * If you want to copy the name string, you can do it by hand:
174
     * <tt>setName(o.getName()</tt>).
175
     *
176
     * Ownership of the object is not affected by assigments.
177
     */
178
    cOwnedObject& operator=(const cOwnedObject& o);
179
180
    // Note: dup() is still the original cObject one, which throws an error
181
    // to indicate that dup() has to be redefined in each subclass.
182
183
    /**
184
     * Serializes the object into a buffer.
185
     */
186
    virtual void parsimPack(cCommBuffer *buffer);
187
188
    /**
189
     * Deserializes the object from a buffer.
190
     */
191
    virtual void parsimUnpack(cCommBuffer *buffer);
192
    //@}
193
194
    /** @name Object ownership */
195
    //@{
196
    /**
197
     * Returns pointer to the owner of the object.
198
     */
199
    virtual cObject *getOwner() const {return ownerp;}
200
201
    /**
202
     * Returns true.
203
     */
204
    virtual bool isOwnedObject() const {return true;}
205
206
    /**
207
     * Returns false in cOwnedObject and in all derived classes except cDefaultList.
208
     * An object A is a "soft owner" if it allows a B object take() an object A owns.
209
     * "Hard owners" will raise an error if some other object tries to take()
210
     * an object they own. The only soft owner class is cDefaultList.
211
     */
212
    virtual bool isSoftOwner() const {return false;}
213
214
    /**
215
     * The object that will be the owner of new or dropped (see drop()) objects.
216
     * The default owner is set internally, it is usually the simple module processing
217
     * the current event.
218
     */
219
    static cDefaultList *getDefaultOwner();
220
    //@}
221
222
    /** @name Statistics. */
223
    //@{
224
    /**
225
     * Returns the total number of objects created since the start of the program
226
     * (or since the last reset). The counter is incremented by cOwnedObject constructor.
227
     * Counter is <tt>signed</tt> to make it easier to detect if it overflows
228
     * during very long simulation runs.
229
     * May be useful for profiling or debugging memory leaks.
230
     */
231
    static long getTotalObjectCount() {return  AO_load(&total_objs);}
232
233
    /**
234
     * Returns the number of objects that currently exist in the program.
235
     * The counter is incremented by cOwnedObject constructor and decremented by
236
     * the destructor.
237
     * May be useful for profiling or debugging memory leaks.
238
     */
239
    static long getLiveObjectCount() {return  AO_load(&live_objs);}
240
241
    /**
242
     * Reset counters used by getTotalObjectCount() and getLiveObjectCount().
243
     * (Note that getLiveObjectCount() may go negative after a reset call.)
244
     */
245
    static void resetObjectCounters()  {AO_store(&total_objs,0); AO_store(&live_objs,0);}
246
247
    /**
248
     * Deletes the object without taking care of the owner. The use of this method
249
     * is discouraged.
250
     *
251
     * Passing NULL is allowed.
252
     *
253
     * @see dropAndDelete()
254
     */
255
    void ignoreOwnerAndDelete(cOwnedObject *obj);
256
257
    //@}
258
};
259
260
261
/**
262
 * Base class for cOwnedObject-based classes that do not wish to support
263
 * assignment and duplication.
264
 *
265
 * @ingroup SimCore
266
 */
267
class SIM_API cNoncopyableOwnedObject : public cOwnedObject, noncopyable
268
{
269
  private:
270
    /**
271
     * Private copy constructor, to prevent copying.
272
     */
273
    cNoncopyableOwnedObject(const cOwnedObject&) {}
274
275
  public:
276
    /**
277
     * Constructor
278
     */
279
    explicit cNoncopyableOwnedObject(const char *name=NULL, bool namepooling=true) :
280
        cOwnedObject(name, namepooling) {}
281
282
    /**
283
     * Duplication not supported, this method is redefined to throw an error.
284
     */
285
    virtual cNoncopyableOwnedObject *dup() const;
286
287
    /**
288
     * Redefined to throw an error.
289
     */
290
    virtual void parsimPack(cCommBuffer *buffer);
291
292
    /**
293
     * Redefined to throw an error.
294
     */
295
    virtual void parsimUnpack(cCommBuffer *buffer);
296
};
297
298
299
//
300
// Internal class: provides a flag that shows if control is in the main() function.
301
//
302
class SIM_API cStaticFlag
303
{
304
  private:
305
    static bool staticflag;  // set to true while in main()
306
    static bool exitingflag; // set on getting a TERM or INT signal (Windows)
307
  public:
308
    cStaticFlag()  {staticflag = true;}
309
    ~cStaticFlag() {staticflag = false;}
310
    static void set(bool b) {staticflag = b;}
311
    static void setExiting() {exitingflag = true;}
312
    static bool isExiting() {return exitingflag;}
313
    static bool isSet() {return staticflag;}
314
};
315
316
SIM_API std::ostream& operator<< (std::ostream& os, const cOwnedObject *p);
317
SIM_API std::ostream& operator<< (std::ostream& os, const cOwnedObject& o);
318
319
inline std::ostream& operator<< (std::ostream& os, cOwnedObject *p) {
320
    return os << (const cOwnedObject *)p;
321
}
322
323
inline std::ostream& operator<< (std::ostream& os, cOwnedObject& o) {
324
    return os << (const cOwnedObject&)o;
325
}
326
327
328
/**
329
 * Cast an object pointer to the given C++ type and throw exception if fails.
330
 * The method calls dynamic_cast\<T\>(p) where T is a type you supplied;
331
 * if the result is NULL (which indicates incompatible types), an exception
332
 * is thrown.
333
 *
334
 * In the following example, MyPacket is a subclass of cMessage, and we want
335
 * to assert that the message received is actually a MyPacket. If not,
336
 * the simulation stops with an error message as the result of the exception.
337
 * <pre>
338
 *   cMessage *msg = receive();
339
 *   MyPacket *pkt = check_and_cast\<MyPacket *\>(msg);
340
 * </pre>
341
 *
342
 * @ingroup Functions
343
 */
344
// Note: this function cannot be put into utils.h (circular dependencies)
345
template<class T>
346
T check_and_cast(cObject *p)
347
{
348
    if (!p)
349
        throw cRuntimeError("check_and_cast(): cannot cast NULL pointer to type '%s'",opp_typename(typeid(T)));
350
    T ret = dynamic_cast<T>(p);
351
    if (!ret)
352
        throw cRuntimeError("check_and_cast(): cannot cast (%s *)%s to type '%s'",p->getClassName(),p->getFullPath().c_str(),opp_typename(typeid(T)));
353
    return ret;
354
}
355
356
/**
357
 * The 'const' version of check_and_cast\<\>().
358
 * @ingroup Functions
359
 */
360
template<class T>
361
const T check_and_cast(const cObject *p)
362
{
363
    return check_and_cast<T>(const_cast<cObject *>(p));
364
}
365
366
NAMESPACE_END
367
368
369
#endif