Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* -*- C++ -*- */ |
2 | /*********************************************************************** | |
3 | * director.swg | |
4 | * | |
5 | * This file contains support for director classes that proxy | |
6 | * method calls from C++ to Ocaml extensions. | |
7 | * | |
8 | * Modified for Ocaml by : Art Yerkes | |
9 | * Original Author : Mark Rose (mrose@stm.lbl.gov) | |
10 | ************************************************************************/ | |
11 | ||
12 | #ifdef __cplusplus | |
13 | ||
14 | #include <string> | |
15 | ||
16 | namespace Swig { | |
17 | /* base class for director exceptions */ | |
18 | class DirectorException { | |
19 | protected: | |
20 | std::string swig_msg; | |
21 | public: | |
22 | DirectorException(const char* msg="") { | |
23 | } | |
24 | const char *getMessage() const { | |
25 | return swig_msg.c_str(); | |
26 | } | |
27 | virtual ~DirectorException() {} | |
28 | }; | |
29 | ||
30 | /* type mismatch in the return value from a python method call */ | |
31 | class DirectorTypeMismatchException : public Swig::DirectorException { | |
32 | public: | |
33 | DirectorTypeMismatchException(const char* msg="") { | |
34 | } | |
35 | }; | |
36 | ||
37 | /* any python exception that occurs during a director method call */ | |
38 | class DirectorMethodException : public Swig::DirectorException {}; | |
39 | ||
40 | /* attempt to call a pure virtual method via a director method */ | |
41 | class DirectorPureVirtualException : public Swig::DirectorException {}; | |
42 | ||
43 | /* simple thread abstraction for pthreads on win32 */ | |
44 | #ifdef __THREAD__ | |
45 | #define __PTHREAD__ | |
46 | #if defined(_WIN32) || defined(__WIN32__) | |
47 | #define pthread_mutex_lock EnterCriticalSection | |
48 | #define pthread_mutex_unlock LeaveCriticalSection | |
49 | #define pthread_mutex_t CRITICAL_SECTION | |
50 | #define MUTEX_INIT(var) CRITICAL_SECTION var | |
51 | #else | |
52 | #include <pthread.h> | |
53 | #define MUTEX_INIT(var) pthread_mutex_t var = PTHREAD_MUTEX_INITIALIZER | |
54 | #endif | |
55 | #endif | |
56 | ||
57 | /* director base class */ | |
58 | class Director { | |
59 | private: | |
60 | /* pointer to the wrapped ocaml object */ | |
61 | CAML_VALUE swig_self; | |
62 | /* flag indicating whether the object is owned by ocaml or c++ */ | |
63 | mutable bool swig_disown_flag; | |
64 | mutable bool swig_up; | |
65 | ||
66 | #ifdef __PTHREAD__ | |
67 | /* locks for sharing the swig_up flag in a threaded environment */ | |
68 | static pthread_mutex_t swig_mutex_up; | |
69 | static bool swig_mutex_active; | |
70 | static pthread_t swig_mutex_thread; | |
71 | #endif | |
72 | ||
73 | /* reset the swig_up flag once the routing direction has been determined */ | |
74 | #ifdef __PTHREAD__ | |
75 | void swig_clear_up() const { | |
76 | swig_up = false; | |
77 | Swig::Director::swig_mutex_active = false; | |
78 | pthread_mutex_unlock(&swig_mutex_up); | |
79 | } | |
80 | ||
81 | #else | |
82 | void swig_clear_up() const { | |
83 | swig_up = false; | |
84 | } | |
85 | #endif | |
86 | ||
87 | public: | |
88 | /* wrap a ocaml object, optionally taking ownership */ | |
89 | Director(CAML_VALUE self) : swig_self(self), swig_disown_flag(false), swig_up( false ) { | |
90 | register_global_root(&swig_self); | |
91 | } | |
92 | ||
93 | /* discard our reference at destruction */ | |
94 | virtual ~Director() { | |
95 | remove_global_root(&swig_self); | |
96 | swig_disown(); | |
97 | // Disown is safe here because we're just divorcing a reference that | |
98 | // points to us. | |
99 | } | |
100 | ||
101 | /* return a pointer to the wrapped ocaml object */ | |
102 | CAML_VALUE swig_get_self() const { | |
103 | return swig_self; | |
104 | } | |
105 | ||
106 | /* get the swig_up flag to determine if the method call should be routed | |
107 | * to the c++ base class or through the wrapped ocaml object | |
108 | */ | |
109 | #ifdef __PTHREAD__ | |
110 | bool swig_get_up( bool clear = true ) const { | |
111 | if (Swig::Director::swig_mutex_active) { | |
112 | if (pthread_equal(Swig::Director::swig_mutex_thread, pthread_self())) { | |
113 | bool up = swig_up; | |
114 | if( clear ) swig_clear_up(); | |
115 | return up; | |
116 | } | |
117 | } | |
118 | return false; | |
119 | } | |
120 | ||
121 | #else | |
122 | bool swig_get_up( bool clear = true ) const { | |
123 | bool up = swig_up; | |
124 | if( clear ) swig_up = false; | |
125 | return up; | |
126 | } | |
127 | #endif | |
128 | ||
129 | /* set the swig_up flag if the next method call should be directed to | |
130 | * the c++ base class rather than the wrapped ocaml object | |
131 | */ | |
132 | #ifdef __PTHREAD__ | |
133 | void swig_set_up() const { | |
134 | pthread_mutex_lock(&Swig::Director::swig_mutex_up); | |
135 | Swig::Director::swig_mutex_thread = pthread_self(); | |
136 | Swig::Director::swig_mutex_active = true; | |
137 | swig_up = true; | |
138 | } | |
139 | #else | |
140 | void swig_set_up() const { | |
141 | swig_up = true; | |
142 | } | |
143 | #endif | |
144 | ||
145 | /* acquire ownership of the wrapped ocaml object (the sense of "disown" | |
146 | * is from ocaml) */ | |
147 | void swig_disown() const { | |
148 | if (!swig_disown_flag) { | |
149 | swig_disown_flag=true; | |
150 | callback(*caml_named_value("caml_obj_disown"),swig_self); | |
151 | } | |
152 | } | |
153 | }; | |
154 | ||
155 | #ifdef __PTHREAD__ | |
156 | MUTEX_INIT(Swig::Director::swig_mutex_up); | |
157 | pthread_t Swig::Director::swig_mutex_thread; | |
158 | bool Swig::Director::swig_mutex_active = false; | |
159 | #endif | |
160 | ||
161 | } | |
162 | ||
163 | #endif /* __cplusplus */ |