1# csrc 2 3The csrc directory contains all of the code concerned with integration 4with Python. This is in contrast to lib, which contains the Torch 5libraries that are Python agnostic. csrc depends on lib, but not vice 6versa. 7 8There are a number of utilities for easing integration with Python which 9are worth knowing about, which we briefly describe here. But the most 10important gotchas: 11 12* DO NOT forget to take out the GIL with `pybind11::gil_scoped_acquire` 13 before calling Python API or bringing a `THPObjectPtr` into scope. 14 15* Make sure you include `Python.h` first in your header files, before 16 any system headers; otherwise, you will get `error: "_XOPEN_SOURCE" redefined` 17 error. If you pay attention to warnings, you will see where you need to 18 do this. 19 20## Notes 21 22### Note [Storage is not nullptr] 23 24Historically, Torch supported nullptr storage, as a minor optimization to 25avoid having to allocate a storage object when it would be empty. 26However, this is actually a confusing special case to deal with, so 27by-in-large, PyTorch assumes that, in fact, storage is never nullptr. 28 29One important case where this assumption is important is when tracking 30the CUDA device a tensor is stored in: this information is stored 31solely in the storage, so if a storage is nullptr, we lose this information. 32 33Although storage is never nullptr, the data field of c10::StorageImpl may be 34nullptr. This 35mostly occurs when we want to pre-allocate an output tensor struct, but then 36have it be resized and filled with data by some operator: there's no point in 37allocating data for it in this case! 38 39## Files 40 41### `Exceptions.h` 42 43Frequently when working with the Python API, you may call a function 44which returns an error. In this case, we want to return directly to the 45Python interpreter, so that this exception can be propagated 46accordingly; however, because the Python API is C-based, what actually 47will happen is it will return control to whatever C++ code called it. 48Similarly, if we raise a C++ exception, prior to returning to the Python 49interpreter, we must set the Python error flags, so it turns into a C++ 50exception. 51 52Moreover, when using the following macros, the generated warnings 53will be converted into python warnings that can be caught by the user. 54 55Exceptions define helpers for two main cases: 56* For code where you write the python binding by hand, `HANDLE_TH_ERRORS`, 57`END_HANDLE_TH_ERRORS` and an exception class `python_error`. You call them like this: 58 59``` 60// Entry point from Python interpreter 61PyObject* run(PyObject* arg) { 62 HANDLE_TH_ERRORS 63 ... 64 if (!x) throw python_error(); 65 // From c10/Exception.h 66 TORCH_CHECK(cond, "cond was false here"); 67 TORCH_WARN("Warning message"); 68 ... 69 END_HANDLE_TH_ERRORS 70} 71``` 72 73The `HANDLE_TH_ERRORS` macro will catch all exceptions and convert them 74into an appropriate Python signal. `python_error` is a special 75exception which doesn't contain any info, instead it says, "An error 76occurred in the Python API; if you return to the interpreter, Python 77will raise that exception, nothing else needs to be done." 78 79* For code that you bind using pybind, `HANDLE_TH_ERRORS` and `END_HANDLE_TH_ERRORS_PYBIND` 80can be used. They will work jointly with pybind error handling to raise 81pytorch errors and warnings natively and let pybind handle other errors. It can be used as: 82 83``` 84// Function given to the pybind binding 85at::Tensor foo(at::Tensor x) { 86 HANDLE_TH_ERRORS 87 ... 88 if (!x) throw python_error(); 89 // pybind native error 90 if (!x) throw py::value_error(); 91 // From c10/Exception.h 92 TORCH_CHECK(cond, "cond was false here"); 93 TORCH_WARN("Warning message"); 94 ... 95 END_HANDLE_TH_ERRORS_PYBIND 96} 97``` 98 99 100### GIL 101 102Whenever you make any calls to the Python API, you must have taken out 103the Python GIL, as none of these calls are thread safe. 104`pybind11::gil_scoped_acquire` is a RAII struct which handles taking and 105releasing the GIL. Use it like this: 106 107``` 108void iWantToUsePython() { 109 pybind11::gil_scoped_acquire gil; 110 ... 111} 112``` 113 114In general, the compiler will NOT warn you if you use Python 115functionality without taking out the GIL, so DO NOT FORGET this call. 116 117### `utils/object_ptr.h` 118 119`THPPointer` is a smart pointer class analogous to `std::shared_ptr`, 120but which is overloaded to handle reference counting scheme of various 121objects which are not based on `shared_ptr`. The most important overloads are: 122 123* `PyObject` (so important we've aliased it as `THPObjectPtr`), which 124 hooks into Python reference counting. (By the way, that means you 125 MUST take out the GIL before bringing one of these into scope!) 126 127* The various TH tensor and storage types (e.g., `THTensor`), which 128 hook into TH's reference counting. (TH's reference counting 129 IS thread safe, no locks necessary.) 130