message_queue.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*************************************************************************/
  2. /* message_queue.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* http://www.godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
  9. /* */
  10. /* Permission is hereby granted, free of charge, to any person obtaining */
  11. /* a copy of this software and associated documentation files (the */
  12. /* "Software"), to deal in the Software without restriction, including */
  13. /* without limitation the rights to use, copy, modify, merge, publish, */
  14. /* distribute, sublicense, and/or sell copies of the Software, and to */
  15. /* permit persons to whom the Software is furnished to do so, subject to */
  16. /* the following conditions: */
  17. /* */
  18. /* The above copyright notice and this permission notice shall be */
  19. /* included in all copies or substantial portions of the Software. */
  20. /* */
  21. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  22. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  23. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  24. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  25. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  26. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  27. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  28. /*************************************************************************/
  29. #include "message_queue.h"
  30. #include "globals.h"
  31. MessageQueue *MessageQueue::singleton=NULL;
  32. MessageQueue *MessageQueue::get_singleton() {
  33. return singleton;
  34. }
  35. Error MessageQueue::push_call(ObjectID p_id, const StringName& p_method, VARIANT_ARG_DECLARE) {
  36. _THREAD_SAFE_METHOD_
  37. uint8_t room_needed=sizeof(Message);
  38. int args=0;
  39. if (p_arg5.get_type()!=Variant::NIL)
  40. args=5;
  41. else if (p_arg4.get_type()!=Variant::NIL)
  42. args=4;
  43. else if (p_arg3.get_type()!=Variant::NIL)
  44. args=3;
  45. else if (p_arg2.get_type()!=Variant::NIL)
  46. args=2;
  47. else if (p_arg1.get_type()!=Variant::NIL)
  48. args=1;
  49. else
  50. args=0;
  51. room_needed+=sizeof(Variant)*args;
  52. if ((buffer_end+room_needed) >= buffer_size) {
  53. String type;
  54. if (ObjectDB::get_instance(p_id))
  55. type=ObjectDB::get_instance(p_id)->get_type();
  56. print_line("failed method: "+type+":"+p_method+" target ID: "+itos(p_id));
  57. statistics();
  58. }
  59. ERR_FAIL_COND_V( (buffer_end+room_needed) >= buffer_size , ERR_OUT_OF_MEMORY );
  60. Message * msg = memnew_placement( &buffer[ buffer_end ], Message );
  61. msg->args=args;
  62. msg->instance_ID=p_id;
  63. msg->target=p_method;
  64. msg->type=TYPE_CALL;
  65. buffer_end+=sizeof(Message);
  66. if (args>=1) {
  67. Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
  68. buffer_end+=sizeof(Variant);
  69. *v=p_arg1;
  70. }
  71. if (args>=2) {
  72. Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
  73. buffer_end+=sizeof(Variant);
  74. *v=p_arg2;
  75. }
  76. if (args>=3) {
  77. Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
  78. buffer_end+=sizeof(Variant);
  79. *v=p_arg3;
  80. }
  81. if (args>=4) {
  82. Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
  83. buffer_end+=sizeof(Variant);
  84. *v=p_arg4;
  85. }
  86. if (args>=5) {
  87. Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
  88. buffer_end+=sizeof(Variant);
  89. *v=p_arg5;
  90. }
  91. return OK;
  92. }
  93. Error MessageQueue::push_set(ObjectID p_id, const StringName& p_prop, const Variant& p_value) {
  94. _THREAD_SAFE_METHOD_
  95. uint8_t room_needed=sizeof(Message)+sizeof(Variant);
  96. if ((buffer_end+room_needed) >= buffer_size) {
  97. String type;
  98. if (ObjectDB::get_instance(p_id))
  99. type=ObjectDB::get_instance(p_id)->get_type();
  100. print_line("failed set: "+type+":"+p_prop+" target ID: "+itos(p_id));
  101. statistics();
  102. }
  103. ERR_FAIL_COND_V( (buffer_end+room_needed) >= buffer_size , ERR_OUT_OF_MEMORY );
  104. Message * msg = memnew_placement( &buffer[ buffer_end ], Message );
  105. msg->args=1;
  106. msg->instance_ID=p_id;
  107. msg->target=p_prop;
  108. msg->type=TYPE_SET;
  109. buffer_end+=sizeof(Message);
  110. Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
  111. buffer_end+=sizeof(Variant);
  112. *v=p_value;
  113. return OK;
  114. }
  115. Error MessageQueue::push_notification(ObjectID p_id, int p_notification) {
  116. _THREAD_SAFE_METHOD_
  117. ERR_FAIL_COND_V(p_notification<0, ERR_INVALID_PARAMETER );
  118. uint8_t room_needed=sizeof(Message);
  119. if ((buffer_end+room_needed) >= buffer_size) {
  120. String type;
  121. if (ObjectDB::get_instance(p_id))
  122. type=ObjectDB::get_instance(p_id)->get_type();
  123. print_line("failed notification: "+itos(p_notification)+" target ID: "+itos(p_id));
  124. statistics();
  125. }
  126. ERR_FAIL_COND_V( (buffer_end+room_needed) >= buffer_size , ERR_OUT_OF_MEMORY );
  127. Message * msg = memnew_placement( &buffer[ buffer_end ], Message );
  128. msg->type=TYPE_NOTIFICATION;
  129. msg->instance_ID=p_id;
  130. //msg->target;
  131. msg->notification=p_notification;
  132. buffer_end+=sizeof(Message);
  133. return OK;
  134. }
  135. Error MessageQueue::push_call(Object *p_object, const StringName& p_method, VARIANT_ARG_DECLARE) {
  136. return push_call(p_object->get_instance_ID(),p_method,VARIANT_ARG_PASS);
  137. }
  138. Error MessageQueue::push_notification(Object *p_object, int p_notification) {
  139. return push_notification(p_object->get_instance_ID(),p_notification);
  140. }
  141. Error MessageQueue::push_set(Object *p_object, const StringName& p_prop, const Variant& p_value) {
  142. return push_set(p_object->get_instance_ID(),p_prop,p_value);
  143. }
  144. void MessageQueue::statistics() {
  145. Map<StringName,int> set_count;
  146. Map<int,int> notify_count;
  147. Map<StringName,int> call_count;
  148. int null_count=0;
  149. uint32_t read_pos=0;
  150. while (read_pos < buffer_end ) {
  151. Message *message = (Message*)&buffer[ read_pos ];
  152. Object *target = ObjectDB::get_instance(message->instance_ID);
  153. if (target!=NULL) {
  154. switch(message->type) {
  155. case TYPE_CALL: {
  156. if (!call_count.has(message->target))
  157. call_count[message->target]=0;
  158. call_count[message->target]++;
  159. } break;
  160. case TYPE_NOTIFICATION: {
  161. if (!notify_count.has(message->notification))
  162. notify_count[message->notification]=0;
  163. notify_count[message->notification]++;
  164. } break;
  165. case TYPE_SET: {
  166. if (!set_count.has(message->target))
  167. set_count[message->target]=0;
  168. set_count[message->target]++;
  169. } break;
  170. }
  171. //object was deleted
  172. //WARN_PRINT("Object was deleted while awaiting a callback")
  173. //should it print a warning?
  174. } else {
  175. null_count++;
  176. }
  177. read_pos+=sizeof(Message);
  178. if (message->type!=TYPE_NOTIFICATION)
  179. read_pos+=sizeof(Variant)*message->args;
  180. }
  181. print_line("TOTAL BYTES: "+itos(buffer_end));
  182. print_line("NULL count: "+itos(null_count));
  183. for(Map<StringName,int>::Element *E=set_count.front();E;E=E->next()) {
  184. print_line("SET "+E->key()+": "+itos(E->get()));
  185. }
  186. for(Map<StringName,int>::Element *E=call_count.front();E;E=E->next()) {
  187. print_line("CALL "+E->key()+": "+itos(E->get()));
  188. }
  189. for(Map<int,int>::Element *E=notify_count.front();E;E=E->next()) {
  190. print_line("NOTIFY "+itos(E->key())+": "+itos(E->get()));
  191. }
  192. }
  193. bool MessageQueue::print() {
  194. #if 0
  195. uint32_t read_pos=0;
  196. while (read_pos < buffer_end ) {
  197. Message *message = (Message*)&buffer[ read_pos ];
  198. Object *target = ObjectDB::get_instance(message->instance_ID);
  199. String cname;
  200. String cfunc;
  201. if (target==NULL) {
  202. //object was deleted
  203. //WARN_PRINT("Object was deleted while awaiting a callback")
  204. //should it print a warning?
  205. } else if (message->notification>=0) {
  206. // messages don't expect a return value
  207. cfunc="notification # "+itos(message->notification);
  208. cname=target->get_type();
  209. } else if (!message->target.empty()) {
  210. cfunc="property: "+message->target;
  211. cname=target->get_type();
  212. } else if (message->target) {
  213. cfunc=String(message->target)+"()";
  214. cname=target->get_type();
  215. }
  216. read_pos+=sizeof(Message);
  217. if (message->type!=TYPE_NOTIFICATION)
  218. read_pos+=sizeof(Variant)*message->args;
  219. }
  220. #endif
  221. return false;
  222. }
  223. int MessageQueue::get_max_buffer_usage() const {
  224. return buffer_max_used;
  225. }
  226. void MessageQueue::flush() {
  227. if (buffer_max_used<buffer_end); {
  228. buffer_max_used=buffer_end;
  229. //statistics();
  230. }
  231. uint32_t read_pos=0;
  232. while (read_pos < buffer_end ) {
  233. //lock on each interation, so a call can re-add itself to the message queue
  234. _THREAD_SAFE_LOCK_
  235. Message *message = (Message*)&buffer[ read_pos ];
  236. Object *target = ObjectDB::get_instance(message->instance_ID);
  237. if (target!=NULL) {
  238. switch(message->type) {
  239. case TYPE_CALL: {
  240. Variant *args= (Variant*)(message+1);
  241. // messages don't expect a return value
  242. target->call( message->target,
  243. (message->args>=1) ? args[0] : Variant(),
  244. (message->args>=2) ? args[1] : Variant(),
  245. (message->args>=3) ? args[2] : Variant(),
  246. (message->args>=4) ? args[3] : Variant(),
  247. (message->args>=5) ? args[4] : Variant() );
  248. for(int i=0;i<message->args;i++) {
  249. args[i].~Variant();
  250. }
  251. } break;
  252. case TYPE_NOTIFICATION: {
  253. // messages don't expect a return value
  254. target->notification(message->notification);
  255. } break;
  256. case TYPE_SET: {
  257. Variant *arg= (Variant*)(message+1);
  258. // messages don't expect a return value
  259. target->set(message->target,*arg);
  260. arg->~Variant();
  261. } break;
  262. }
  263. }
  264. read_pos+=sizeof(Message);
  265. if (message->type!=TYPE_NOTIFICATION)
  266. read_pos+=sizeof(Variant)*message->args;
  267. message->~Message();
  268. _THREAD_SAFE_UNLOCK_
  269. }
  270. _THREAD_SAFE_LOCK_
  271. buffer_end=0; // reset buffer
  272. _THREAD_SAFE_UNLOCK_
  273. }
  274. MessageQueue::MessageQueue() {
  275. ERR_FAIL_COND(singleton!=NULL);
  276. singleton=this;
  277. buffer_end=0;
  278. buffer_max_used=0;
  279. buffer_size=GLOBAL_DEF( "core/message_queue_size_kb", DEFAULT_QUEUE_SIZE_KB );
  280. buffer_size*=1024;
  281. buffer = memnew_arr( uint8_t, buffer_size );
  282. }
  283. MessageQueue::~MessageQueue() {
  284. uint32_t read_pos=0;
  285. while (read_pos < buffer_end ) {
  286. Message *message = (Message*)&buffer[ read_pos ];
  287. Variant *args= (Variant*)(message+1);
  288. int argc = message->args;
  289. if (message->type!=TYPE_NOTIFICATION) {
  290. for (int i=0;i<argc;i++)
  291. args[i].~Variant();
  292. }
  293. message->~Message();
  294. read_pos+=sizeof(Message);
  295. if (message->type!=TYPE_NOTIFICATION)
  296. read_pos+=sizeof(Variant)*message->args;
  297. }
  298. singleton=NULL;
  299. memdelete_arr( buffer );
  300. }