| 306 | bool IsExpensive() override { return true; } |
| 307 | |
| 308 | void Compute(OpKernelContext* ctx) override { |
| 309 | PyCall call; |
| 310 | call.token = token_; |
| 311 | call.eager = eager_; |
| 312 | if (call.eager) { |
| 313 | // Eager's C API uses `Device`, whereas `OpKernelContext` stores a |
| 314 | // `DeviceBase`; attempt to downcast. |
| 315 | call.device = dynamic_cast<Device*>(ctx->device()); |
| 316 | if (call.device == nullptr) { |
| 317 | ctx->CtxFailureWithWarning(errors::Internal( |
| 318 | "Unrecognized device class: ", ctx->device()->name())); |
| 319 | return; |
| 320 | } |
| 321 | call.eager_async = eager_async_; |
| 322 | } |
| 323 | |
| 324 | for (int i = 0; i < ctx->num_inputs(); ++i) { |
| 325 | call.ins.push_back(ctx->input(i)); |
| 326 | } |
| 327 | |
| 328 | // NOTE(mrry): There is a potential time-of-check-to-time-of-use race here. |
| 329 | // because it is possible that `Py_Finalize()` could be called in another |
| 330 | // thread between this check and the call to `PyGILState_Ensure()`, which |
| 331 | // will abort the process if `Py_Finalize()` has been called. A more robust |
| 332 | // solution would be welcome, but it is not obvious how to make this work |
| 333 | // using the current Python C API. |
| 334 | OP_REQUIRES(ctx, Py_IsInitialized(), |
| 335 | errors::FailedPrecondition( |
| 336 | "Python interpreter state is not initialized. " |
| 337 | "The process may be terminated.")); |
| 338 | |
| 339 | PyGILState_STATE py_threadstate; |
| 340 | py_threadstate = PyGILState_Ensure(); |
| 341 | bool log_on_error; |
| 342 | Status s = DoCallPyFunc(&call, &log_on_error); |
| 343 | // Sometimes py_funcs can be called without a session and leak memory. This |
| 344 | // ensures we clear the decref cache so this doesn't happen. |
| 345 | ClearDecrefCache(); |
| 346 | PyGILState_Release(py_threadstate); |
| 347 | |
| 348 | // Ensures that GIL is released even when !s.ok(). |
| 349 | if (!s.ok()) { |
| 350 | if (log_on_error) { |
| 351 | ctx->CtxFailureWithWarning(s); |
| 352 | } else { |
| 353 | ctx->CtxFailure(s); |
| 354 | } |
| 355 | return; |
| 356 | } |
| 357 | |
| 358 | OP_REQUIRES(ctx, static_cast<int32>(call.out.size()) == ctx->num_outputs(), |
| 359 | errors::InvalidArgument(token_, " returns ", call.out.size(), |
| 360 | " values, but expects to see ", |
| 361 | ctx->num_outputs(), " values.")); |
| 362 | for (size_t i = 0; i < call.out.size(); ++i) { |
| 363 | const auto& t = call.out[i]; |
| 364 | OP_REQUIRES( |
| 365 | ctx, t.dtype() == output_type(i), |
nothing calls this directly
no test coverage detected