Browse Source

support BLOCKING keyword

David Rose 18 years ago
parent
commit
346928ece7

+ 5 - 0
dtool/src/cppparser/cppBison.yxx

@@ -236,6 +236,7 @@ pop_struct() {
 %token TOKENPASTE
 %token TOKENPASTE
 
 
 %token KW_BEGIN_PUBLISH
 %token KW_BEGIN_PUBLISH
+%token KW_BLOCKING
 %token KW_BOOL
 %token KW_BOOL
 %token KW_CATCH
 %token KW_CATCH
 %token KW_CHAR
 %token KW_CHAR
@@ -531,6 +532,10 @@ storage_class:
         | storage_class KW_REGISTER
         | storage_class KW_REGISTER
 {
 {
   $$ = $1 | (int)CPPInstance::SC_register;
   $$ = $1 | (int)CPPInstance::SC_register;
+}
+        | storage_class KW_BLOCKING
+{
+  $$ = $1 | (int)CPPInstance::SC_blocking;
 }
 }
         ;
         ;
 
 

+ 6 - 0
dtool/src/cppparser/cppInstance.h

@@ -54,6 +54,12 @@ public:
 
 
     // This bit is only set by CPPStructType::check_virtual().
     // This bit is only set by CPPStructType::check_virtual().
     SC_inherited_virtual = 0x400,
     SC_inherited_virtual = 0x400,
+
+    // This is a special "storage class" for methods tagged with the
+    // BLOCKING macro (i.e. the special __blocking keyword).  These
+    // are methods that might block and therefore need to release
+    // Python threads for their duration.
+    SC_blocking     = 0x800,
   };
   };
 
 
   CPPInstance(CPPType *type, const string &name, int storage_class = 0);
   CPPInstance(CPPType *type, const string &name, int storage_class = 0);

+ 1 - 0
dtool/src/cppparser/cppPreprocessor.cxx

@@ -1929,6 +1929,7 @@ get_number(int c, int c2) {
 int CPPPreprocessor::
 int CPPPreprocessor::
 check_keyword(const string &name) {
 check_keyword(const string &name) {
   if (name == "__begin_publish") return KW_BEGIN_PUBLISH;
   if (name == "__begin_publish") return KW_BEGIN_PUBLISH;
+  if (name == "__blocking") return KW_BLOCKING;
   if (name == "bool") return KW_BOOL;
   if (name == "bool") return KW_BOOL;
   if (name == "catch") return KW_CATCH;
   if (name == "catch") return KW_CATCH;
   if (name == "char") return KW_CHAR;
   if (name == "char") return KW_CHAR;

+ 5 - 1
dtool/src/dtoolbase/dtoolbase.h

@@ -277,15 +277,19 @@
 /*
 /*
  We define the macros BEGIN_PUBLISH and END_PUBLISH to bracket
  We define the macros BEGIN_PUBLISH and END_PUBLISH to bracket
  functions and global variable definitions that are to be published
  functions and global variable definitions that are to be published
- via interrogate to scripting languages.
+ via interrogate to scripting languages.  Also, the macro BLOCKING is
+ used to flag any function or method that might perform I/O blocking
+ and thus needs to release Python threads for its duration.
  */
  */
 #ifdef CPPPARSER
 #ifdef CPPPARSER
 #define BEGIN_PUBLISH __begin_publish
 #define BEGIN_PUBLISH __begin_publish
 #define END_PUBLISH __end_publish
 #define END_PUBLISH __end_publish
+#define BLOCKING __blocking
 #undef USE_STL_ALLOCATOR  // Don't try to parse these template classes in interrogate.
 #undef USE_STL_ALLOCATOR  // Don't try to parse these template classes in interrogate.
 #else
 #else
 #define BEGIN_PUBLISH
 #define BEGIN_PUBLISH
 #define END_PUBLISH
 #define END_PUBLISH
+#define BLOCKING
 #endif
 #endif
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 7 - 0
dtool/src/interrogate/functionRemap.cxx

@@ -47,6 +47,7 @@ FunctionRemap(const InterrogateType &itype, const InterrogateFunction &ifunc,
   _void_return = true;
   _void_return = true;
   _ForcedVoidReturn = false;
   _ForcedVoidReturn = false;
   _has_this = false;
   _has_this = false;
+  _blocking = false;
   _const_method = false;
   _const_method = false;
   _first_true_parameter = 0;
   _first_true_parameter = 0;
   _num_default_parameters = num_default_parameters;
   _num_default_parameters = num_default_parameters;
@@ -438,6 +439,12 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
     _type = T_setter;
     _type = T_setter;
   }
   }
 
 
+  if (_cpptype != (CPPType *)NULL &&
+      ((_cppfunc->_storage_class & CPPInstance::SC_blocking) != 0)) {
+    // If it's marked as a "blocking" method or function, record that.
+    _blocking = true;
+  }
+
   if (_cpptype != (CPPType *)NULL &&
   if (_cpptype != (CPPType *)NULL &&
       ((_cppfunc->_storage_class & CPPInstance::SC_static) == 0) &&
       ((_cppfunc->_storage_class & CPPInstance::SC_static) == 0) &&
       _type != T_constructor) {
       _type != T_constructor) {

+ 1 - 0
dtool/src/interrogate/functionRemap.h

@@ -89,6 +89,7 @@ public:
   bool _void_return;
   bool _void_return;
   bool _ForcedVoidReturn;
   bool _ForcedVoidReturn;
   bool _has_this;
   bool _has_this;
+  bool _blocking;
   bool _const_method;
   bool _const_method;
   int _first_true_parameter;
   int _first_true_parameter;
   int _num_default_parameters;
   int _num_default_parameters;

+ 28 - 0
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -2275,6 +2275,12 @@ void InterfaceMakerPythonNative::write_function_instance(ostream &out, Interface
       remap->_return_type->new_type_is_atomic_string()) {
       remap->_return_type->new_type_is_atomic_string()) {
     // Treat strings as a special case.  We don't want to format the
     // Treat strings as a special case.  We don't want to format the
     // return expression.
     // return expression.
+    if (remap->_blocking) {
+      indent(out, extra_indent_level)
+        << "PyThreadState *_save;\n";
+      indent(out, extra_indent_level)
+        << "Py_UNBLOCK_THREADS\n";
+    }
     string tt;
     string tt;
     string return_expr = remap->call_function(out, extra_indent_level, false, container, pexprs);
     string return_expr = remap->call_function(out, extra_indent_level, false, container, pexprs);
     CPPType *type = remap->_return_type->get_orig_type();
     CPPType *type = remap->_return_type->get_orig_type();
@@ -2282,6 +2288,11 @@ void InterfaceMakerPythonNative::write_function_instance(ostream &out, Interface
     type->output_instance(out, "return_value", &parser);
     type->output_instance(out, "return_value", &parser);
     //    type->output_instance(tt, "return_value", &parser);
     //    type->output_instance(tt, "return_value", &parser);
     out << " = " << return_expr << ";\n";
     out << " = " << return_expr << ";\n";
+
+    if (remap->_blocking) {
+      indent(out, extra_indent_level)
+        << "Py_BLOCK_THREADS\n";
+    }
     
     
     if (track_interpreter) {
     if (track_interpreter) {
       indent(out,extra_indent_level) << "in_interpreter = 1;\n";
       indent(out,extra_indent_level) << "in_interpreter = 1;\n";
@@ -2295,8 +2306,20 @@ void InterfaceMakerPythonNative::write_function_instance(ostream &out, Interface
     pack_return_value(out, extra_indent_level, remap, return_expr,ForwardDeclrs,is_inplace);
     pack_return_value(out, extra_indent_level, remap, return_expr,ForwardDeclrs,is_inplace);
 
 
   } else {
   } else {
+    if (remap->_blocking) {
+      indent(out, extra_indent_level)
+        << "PyThreadState *_save;\n";
+      indent(out, extra_indent_level)
+        << "Py_UNBLOCK_THREADS\n";
+    }
+
     string return_expr = remap->call_function(out, extra_indent_level, true, container, pexprs);
     string return_expr = remap->call_function(out, extra_indent_level, true, container, pexprs);
     if (return_expr.empty()) {
     if (return_expr.empty()) {
+      if (remap->_blocking) {
+        indent(out, extra_indent_level)
+          << "Py_BLOCK_THREADS\n";
+      }
+
       if (track_interpreter) {
       if (track_interpreter) {
         indent(out,extra_indent_level) << "in_interpreter = 1;\n";
         indent(out,extra_indent_level) << "in_interpreter = 1;\n";
       }
       }
@@ -2313,6 +2336,11 @@ void InterfaceMakerPythonNative::write_function_instance(ostream &out, Interface
         type->output_instance(out, "return_value", &parser);
         type->output_instance(out, "return_value", &parser);
         out << " = " << return_expr << ";\n";
         out << " = " << return_expr << ";\n";
       }
       }
+      if (remap->_blocking) {
+        indent(out, extra_indent_level)
+          << "Py_BLOCK_THREADS\n";
+      }
+
       if (track_interpreter) {
       if (track_interpreter) {
         indent(out,extra_indent_level) << "in_interpreter = 1;\n";
         indent(out,extra_indent_level) << "in_interpreter = 1;\n";
       }
       }