| /**************************************************************************** |
| * libs/libc/stdlib/lib_atexit.c |
| * |
| * 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. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <stdlib.h> |
| |
| #include <nuttx/atexit.h> |
| #include <nuttx/mutex.h> |
| #include <nuttx/tls.h> |
| |
| #if CONFIG_LIBC_MAX_EXITFUNS > 0 |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: get_exitfuncs |
| * |
| * Description: |
| * Obtain the list of exit functions. |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * Pointer to the list of exit functions. |
| * |
| ****************************************************************************/ |
| |
| static FAR struct atexit_list_s *get_exitfuncs(void) |
| { |
| FAR struct task_info_s *info; |
| |
| info = task_get_info(); |
| return &info->ta_exit; |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| int atexit_register(int type, CODE void (*func)(void), FAR void *arg, |
| FAR void *dso) |
| { |
| FAR struct task_info_s *info = task_get_info(); |
| FAR struct atexit_list_s *aehead; |
| int idx; |
| int ret = ERROR; |
| |
| /* REVISIT: Missing logic */ |
| |
| UNUSED(dso); |
| |
| /* The following must be atomic */ |
| |
| aehead = get_exitfuncs(); |
| |
| if (func) |
| { |
| ret = nxmutex_lock(&info->ta_lock); |
| if (ret < 0) |
| { |
| return -ret; |
| } |
| |
| if ((idx = aehead->nfuncs) < ATEXIT_MAX) |
| { |
| aehead->funcs[idx].type = type; |
| aehead->funcs[idx].func = func; |
| aehead->funcs[idx].arg = arg; |
| aehead->nfuncs++; |
| ret = OK; |
| } |
| else |
| { |
| ret = ERROR; |
| } |
| |
| nxmutex_unlock(&info->ta_lock); |
| } |
| |
| return ret; |
| } |
| |
| void atexit_call_exitfuncs(int status, bool quick) |
| { |
| FAR struct atexit_list_s *aehead; |
| CODE void (*func)(void); |
| FAR void *arg; |
| int idx; |
| int type; |
| |
| /* Call exit functions in reverse order */ |
| |
| aehead = get_exitfuncs(); |
| |
| for (idx = aehead->nfuncs - 1; idx >= 0; idx--) |
| { |
| /* Remove the function to prevent recursive call to it */ |
| |
| type = aehead->funcs[idx].type; |
| |
| func = aehead->funcs[idx].func; |
| arg = aehead->funcs[idx].arg; |
| |
| aehead->funcs[idx].func = NULL; |
| aehead->funcs[idx].arg = NULL; |
| |
| if (!func) |
| { |
| continue; |
| } |
| |
| if (quick != (type == ATTYPE_ATQUICKEXIT)) |
| { |
| continue; |
| } |
| |
| /* Call the atexit/on_exit/cxa_atexit() function */ |
| |
| if (type == ATTYPE_ATEXIT || type == ATTYPE_ATQUICKEXIT) |
| { |
| (*func)(); |
| } |
| else if (type == ATTYPE_ONEXIT) |
| { |
| (*((CODE void (*)(int, FAR void *))func))(status, arg); |
| } |
| else if (type == ATTYPE_CXA) |
| { |
| (*((CODE void (*)(FAR void *))func))(arg); |
| } |
| } |
| } |
| |
| #endif |
| |
| /**************************************************************************** |
| * Name: atexit |
| * |
| * Description: |
| * Registers a function to be called at program exit. |
| * The atexit() function registers the given function to be called |
| * at normal process termination, whether via exit or via return from |
| * the program's main(). |
| * |
| * Limitations in the current implementation: |
| * |
| * 1. Only a single atexit function can be registered unless |
| * CONFIG_LIBC_MAX_EXITFUNS defines a larger number. |
| * 2. atexit functions are not inherited when a new task is |
| * created. |
| * |
| * Input Parameters: |
| * func - A pointer to the function to be called when the task exits. |
| * |
| * Returned Value: |
| * Zero on success. Non-zero on failure. |
| * |
| ****************************************************************************/ |
| |
| int atexit(CODE void (*func)(void)) |
| { |
| return atexit_register(ATTYPE_ATEXIT, func, NULL, NULL); |
| } |
| |
| /**************************************************************************** |
| * Name: at_quick_exit |
| * |
| * Description: |
| * Registers the function pointed to by func to be called on quick |
| * program termination (via quick_exit). |
| * |
| * Input Parameters: |
| * func - A pointer to the function to be called when the task exits. |
| * |
| * Returned Value: |
| * Zero on success. Non-zero on failure. |
| * |
| ****************************************************************************/ |
| |
| int at_quick_exit(CODE void (*func)(void)) |
| { |
| return atexit_register(ATTYPE_ATQUICKEXIT, func, NULL, NULL); |
| } |
| |
| /**************************************************************************** |
| * Name: on_exit |
| * |
| * Description: |
| * Registers a function to be called at program exit. |
| * The on_exit() function registers the given function to be called |
| * at normal process termination, whether via exit or via return from |
| * the program's main(). The function is passed the status argument |
| * given to the last call to exit and the arg argument from on_exit(). |
| * |
| * NOTE 1: This function comes from SunOS 4, but is also present in |
| * libc4, libc5 and glibc. It no longer occurs in Solaris (SunOS 5). |
| * Avoid this function, and use the standard atexit() instead. |
| * |
| * Limitations in the current implementation: |
| * |
| * 1. Only a single on_exit function can be registered unless |
| * CONFIG_LIBC_MAX_EXITFUNS defines a larger number. |
| * 2. on_exit functions are not inherited when a new task is |
| * created. |
| * |
| * Input Parameters: |
| * func - A pointer to the function to be called when the task exits. |
| * arg - An argument that will be provided to the on_exit() function when |
| * the task exits. |
| * |
| * Returned Value: |
| * Zero on success. Non-zero on failure. |
| * |
| ****************************************************************************/ |
| |
| int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg) |
| { |
| return atexit_register(ATTYPE_ONEXIT, (CODE void (*)(void))func, arg, |
| NULL); |
| } |
| |
| /**************************************************************************** |
| * Name: __cxa_atexit |
| * |
| * Description: |
| * __cxa_atexit() registers a destructor function to be called by exit(). |
| * On a call to exit(), the registered functions should be called with |
| * the single argument 'arg'. Destructor functions shall always be |
| * called in the reverse order to their registration (i.e. the most |
| * recently registered function shall be called first), |
| * |
| * If shared libraries were supported, the callbacks should be invoked |
| * when the shared library is unloaded as well. |
| * |
| * Reference: |
| * Linux base |
| * |
| ****************************************************************************/ |
| |
| int __cxa_atexit(CODE void (*func)(FAR void *), FAR void *arg, |
| FAR void *dso_handle) |
| { |
| return atexit_register(ATTYPE_CXA, (CODE void (*)(void))func, arg, |
| dso_handle); |
| } |