| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| #include "platform.h" |
| |
| #include "Exception.h" |
| #include "ExceptionInternal.h" |
| #include "Thread.h" |
| |
| #include <cstring> |
| #include <cassert> |
| #include <sstream> |
| |
| namespace Yarn { |
| |
| function<bool(void)> ChecnOperationCanceledCallback; |
| |
| namespace Internal { |
| |
| bool CheckOperationCanceled() { |
| if (ChecnOperationCanceledCallback && ChecnOperationCanceledCallback()) { |
| THROW(YarnCanceled, "Operation has been canceled by the user."); |
| } |
| |
| return false; |
| } |
| |
| const char * GetSystemErrorInfo(int eno) { |
| static THREAD_LOCAL char message[64]; |
| char buffer[64], *pbuffer; |
| pbuffer = buffer; |
| #ifdef STRERROR_R_RETURN_INT |
| strerror_r(eno, buffer, sizeof(buffer)); |
| #else |
| pbuffer = strerror_r(eno, buffer, sizeof(buffer)); |
| #endif |
| snprintf(message, sizeof(message), "(errno: %d) %s", eno, pbuffer); |
| return message; |
| } |
| |
| |
| static void GetExceptionDetailInternal(const Yarn::YarnException & e, |
| std::stringstream & ss, bool topLevel); |
| |
| static void GetExceptionDetailInternal(const std::exception & e, |
| std::stringstream & ss, bool topLevel) { |
| try { |
| if (!topLevel) { |
| ss << "Caused by\n"; |
| } |
| |
| ss << e.what(); |
| } catch (const std::bad_alloc & e) { |
| return; |
| } |
| |
| try { |
| Yarn::rethrow_if_nested(e); |
| } catch (const Yarn::YarnException & e) { |
| GetExceptionDetailInternal(e, ss, false); |
| } catch (const std::exception & nested) { |
| GetExceptionDetailInternal(e, ss, false); |
| } |
| } |
| |
| static void GetExceptionDetailInternal(const Yarn::YarnException & e, |
| std::stringstream & ss, bool topLevel) { |
| try { |
| if (!topLevel) { |
| ss << "Caused by\n"; |
| } |
| |
| ss << e.msg(); |
| } catch (const std::bad_alloc & e) { |
| return; |
| } |
| |
| try { |
| Yarn::rethrow_if_nested(e); |
| } catch (const Yarn::YarnException & e) { |
| GetExceptionDetailInternal(e, ss, false); |
| } catch (const std::exception & nested) { |
| GetExceptionDetailInternal(e, ss, false); |
| } |
| } |
| |
| const char * GetExceptionDetail(const Yarn::YarnException & e, |
| std::string& buffer) { |
| try { |
| std::stringstream ss; |
| ss.imbue(std::locale::classic()); |
| GetExceptionDetailInternal(e, ss, true); |
| buffer = ss.str(); |
| } catch (const std::bad_alloc& e) { |
| return "Out of memory"; |
| } |
| |
| return buffer.c_str(); |
| } |
| |
| const char * GetExceptionDetail(const exception_ptr e, std::string& buffer) { |
| std::stringstream ss; |
| ss.imbue(std::locale::classic()); |
| |
| try { |
| Yarn::rethrow_exception(e); |
| } catch (const Yarn::YarnException & nested) { |
| GetExceptionDetailInternal(nested, ss, true); |
| } catch (const std::exception & nested) { |
| GetExceptionDetailInternal(nested, ss, true); |
| } |
| |
| try { |
| buffer = ss.str(); |
| } catch (const std::bad_alloc& e) { |
| return "Out of memory"; |
| } |
| |
| return buffer.c_str(); |
| } |
| |
| static void GetExceptionMessage(const std::exception & e, |
| std::stringstream & ss, int recursive) { |
| try { |
| for (int i = 0; i < recursive; ++i) { |
| ss << '\t'; |
| } |
| |
| if (recursive > 0) { |
| ss << "Caused by: "; |
| } |
| |
| ss << e.what(); |
| } catch (const std::bad_alloc & e) { |
| return; |
| } |
| |
| try { |
| Yarn::rethrow_if_nested(e); |
| } catch (const std::exception & nested) { |
| GetExceptionMessage(nested, ss, recursive + 1); |
| } |
| } |
| |
| const char * GetExceptionMessage(const exception_ptr e, std::string & buffer) { |
| std::stringstream ss; |
| ss.imbue(std::locale::classic()); |
| |
| try { |
| Yarn::rethrow_exception(e); |
| } catch (const std::bad_alloc & e) { |
| return "Out of memory"; |
| } catch (const std::exception & e) { |
| GetExceptionMessage(e, ss, 0); |
| } |
| |
| try { |
| buffer = ss.str(); |
| } catch (const std::bad_alloc & e) { |
| return "Out of memory"; |
| } |
| |
| return buffer.c_str(); |
| } |
| |
| } |
| } |
| |