X-Git-Url: https://git.saurik.com/apple/libc.git/blobdiff_plain/70ad1dc8a19d6edd9b97aa81f32cfd65758ae97d..refs/heads/master:/libdarwin/h/cleanup.h?ds=sidebyside diff --git a/libdarwin/h/cleanup.h b/libdarwin/h/cleanup.h index c74c8f1..cbbd045 100644 --- a/libdarwin/h/cleanup.h +++ b/libdarwin/h/cleanup.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -50,10 +51,16 @@ #include #include #include +#include #include #include #include #include +#include + +#if DARWIN_TAPI +#include "tapi.h" +#endif __BEGIN_DECLS; @@ -97,7 +104,7 @@ __os_cleanup_close(int *__fd) * @define __os_fclose * An attribute that may be applied to a variable's type. This attribute causes * the variable to be passed to fclose(3) when it goes out of scope. Applying - * this attribute to variables that do not reference a valid FILE* will result + * this attribute to variables that do not reference a valid FILE * will result * in undefined behavior. If the variable's value is NULL upon going out-of- * scope, no cleanup is performed. */ @@ -118,14 +125,34 @@ __os_cleanup_fclose(FILE **__fp) } } +/*! + * @define __os_closedir + * An attribute that may be applied to a variable's type. This attribute causes + * the variable to be passed to closedir(3) when it goes out of scope. Applying + * this attribute to variables that do not reference a valid DIR * will result + * in undefined behavior. If the variable's value is NULL upon going out-of- + * scope, no cleanup is performed. + */ +#define __os_closedir __attribute__((cleanup(__os_cleanup_closedir))) +static inline void +__os_cleanup_closedir(DIR **__dp) +{ + DIR *dp = *__dp; + + if (!dp) { + return; + } + posix_assert_zero(closedir(dp)); +} + /*! * @define __os_close_mach_recv * An attribute that may be applied to a variable's type. This attribute causes - * the variable to be passed to {@link darwin_mach_port_close_recv} when it goes - * out of scope. Applying this attribute to variables that do not reference a - * valid Mach port receive right will result in undefined behavior. If the - * variable's value is MACH_PORT_NULL or MACH_PORT_DEAD upon going out-of-scope, - * no cleanup is performed. + * the variable to be wrapped in a mach receive right object and passed to + * {@link mach_right_recv_destruct} when it goes out of scope. Applying this + * attribute to variables that do not reference a valid Mach port receive right + * will result in undefined behavior. If the variable's value is MACH_PORT_NULL + * or MACH_PORT_DEAD upon going out-of-scope, no cleanup is performed. */ #define __os_close_mach_recv \ __attribute__((cleanup(__os_cleanup_close_mach_recv))) @@ -133,24 +160,24 @@ static inline void __os_cleanup_close_mach_recv(mach_port_t *__p) { mach_port_t p = *__p; - kern_return_t kr = KERN_FAILURE; + mach_right_recv_t mr = mach_right_recv(p); if (!MACH_PORT_VALID(p)) { return; } - kr = mach_port_destruct(mach_task_self(), p, 0, 0); - os_assert_zero(kr); + mach_right_recv_destruct(mr, NULL, 0); } /*! * @define __os_release_mach_send * An attribute that may be applied to a variable's type. This attribute causes - * the variable to be passed to {@link darwin_mach_port_release} when it goes - * out of scope. Applying this attribute to variables that do not reference a - * valid Mach port send right or MACH_PORT_NULL or MACH_PORT_DEAD will result - * in undefined behavior. If the variable's value is MACH_PORT_NULL or - * MACH_PORT_DEAD upon going out-of-scope, no cleanup is performed. + * the variable to be wrapped in a mach send right object and passed to + * {@link mach_right_send_release} when it goes out of scope. Applying this + * attribute to variables that do not reference a valid Mach port send right or + * MACH_PORT_NULL or MACH_PORT_DEAD will result in undefined behavior. If the + * variable's value is MACH_PORT_NULL or MACH_PORT_DEAD upon going out-of-scope, + * no cleanup is performed. */ #define __os_release_mach_send \ __attribute__((cleanup(__os_cleanup_release_mach_send))) @@ -158,14 +185,13 @@ static inline void __os_cleanup_release_mach_send(mach_port_t *__p) { mach_port_t p = *__p; - kern_return_t kr = KERN_FAILURE; + mach_right_send_t ms = mach_right_send(p); if (!MACH_PORT_VALID(p)) { return; } - kr = mach_port_deallocate(mach_task_self(), p); - os_assert_zero(kr); + mach_right_send_release(ms); } /*! @@ -192,7 +218,12 @@ __os_cleanup_errno(int *__e) * upon going out-of-scope, no cleanup is performed. * * This attribute may be applied to dispatch and XPC objects. + * + * When compiling with ARC, this attribute does nothing. */ +#if __has_feature(objc_arc) +#define __os_release +#else #define __os_release __attribute__((cleanup(__os_cleanup_os_release))) static inline void __os_cleanup_os_release(void *__p) @@ -204,8 +235,9 @@ __os_cleanup_os_release(void *__p) } os_release(o); } +#endif -#if __COREFOUNDATION__ +#if DARWIN_CLEANUP_CF /*! * @define __os_cfrelease * An attribute that may be applied to a variable's type. This attribute causes @@ -213,6 +245,9 @@ __os_cleanup_os_release(void *__p) * this attribute to a variable which does not reference a valid CoreFoundation * object will result in undefined behavior. If the variable's value is NULL * upon going out-of-scope, no cleanup is performed. + * + * In order to use, you must define the DARWIN_CLEANUP_CF macro to 1 prior to + * including this header. */ #define __os_cfrelease __attribute__((cleanup(__os_cleanup_cfrelease))) static inline void @@ -225,17 +260,119 @@ __os_cleanup_cfrelease(void *__p) } CFRelease(cf); } -#endif // __COREFOUNDATION__ +#endif // DARWIN_CLEANUP_CF + +#if DARWIN_CLEANUP_IOKIT +/*! + * @define __os_iorelease + * An attribute that may be applied to a variable's type. This attribute causes + * the variable to be passed to IOObjectRelease() when it goes out of scope. + * Applying this attribute to a variable which does not reference a valid IOKit + * object will result in undefined behavior. If the variable's value is + * IO_OBJECT_NULL upon going out-of-scope, no cleanup is performed. + * + * + * In order to use, you must define the DARWIN_CLEANUP_IOKIT macro to 1 prior to + * including this header. + */ +#define __os_iorelease __attribute__((cleanup(__os_cleanup_iorelease))) +static inline void +__os_cleanup_iorelease(void *__p) +{ + kern_return_t kr = KERN_FAILURE; + io_object_t *iop = (io_object_t *)__p; + io_object_t io = *iop; + + if (io == IO_OBJECT_NULL) { + return; + } + + kr = IOObjectRelease(io); + if (kr) { + os_crash("IOObjectRetain: %{mach.errno}d", kr); + } +} + +/*! + * @define __os_ioclose + * An attribute that may be applied to a variable's type. This attribute causes + * the variable to be passed to IOServiceClose() when it goes out of scope. + * Applying this attribute to a variable which does not reference a valid IOKit + * connection will result in undefined behavior. If the variable's value is + * IO_OBJECT_NULL upon going out-of-scope, no cleanup is performed. + * + * In order to use, you must define the DARWIN_CLEANUP_IOKIT macro to 1 prior to + * including this header. + */ +#define __os_ioclose __attribute__((cleanup(__os_cleanup_ioclose))) +static inline void +__os_cleanup_ioclose(void *__p) +{ + kern_return_t kr = KERN_FAILURE; + io_connect_t *iop = (io_object_t *)__p; + io_connect_t io = *iop; + + if (io == IO_OBJECT_NULL) { + return; + } + + kr = IOServiceClose(io); + if (kr) { + os_crash("IOObjectRelease: %{mach.errno}d", kr); + } +} +#endif // DARWIN_CLEANUP_IOKIT + +/*! + * @define __os_unfair_unlock + * An attribute that may be applied to a variable's type. This attribute causes + * the variable to be passed to os_unfair_lock_unlock() when it goes out of + * scope. Applying this attribute to a variable which does not reference a valid + * os_unfair_lock_t object will result in undefined behavior. If the variable's + * value is NULL upon going out-of-scope, no cleanup is performed. + * + * This attribute is useful even when the target lock is taken conditionally via + * the following pattern: + * + * os_unfair_lock lock = OS_UNFAIR_LOCK_INIT; + * os_unfair_lock_t __os_unfair_unlock l2un = NULL; + * + * if (take_the_lock) { + * os_unfair_lock_lock(&lock); + * + * // Guarantee that 'lock' will be unconditionally released when the + * // scope containing 'l2un' ends. + * l2un = &lock; + * } + */ +#define __os_unfair_unlock __attribute__((cleanup(__os_cleanup_unfair_unlock))) +static inline void +__os_cleanup_unfair_unlock(void *__p) +{ + os_unfair_lock_t *tp = (os_unfair_lock_t *)__p; + os_unfair_lock_t ufl = *tp; + if (!ufl) { + return; + } + os_unfair_lock_assert_owner(ufl); + os_unfair_lock_unlock(ufl); +} #else // __has_attribute(cleanup) -#define __os_free __attribute__((__os_not_supported)) -#define __os_close __attribute__((__os_not_supported)) -#define __os_fclose __attribute__((__os_not_supported)) -#define __os_close_mach_recv __attribute__((__os_not_supported)) -#define __os_release_mach_send __attribute__((__os_not_supported)) -#define __os_preserve_errno __attribute__((__os_not_supported)) -#define __os_release __attribute__((__os_not_supported)) -#define __os_cfrelease __attribute__((__os_not_supported)) +#define __os_cleanup_unsupported \ + _Pragma("GCC error \"automatic cleanup not supported\"") +#define __os_free __os_cleanup_unsupported +#define __os_close __os_cleanup_unsupported +#define __os_fclose __os_cleanup_unsupported +#define __os_closedir __os_cleanup_unsupported +#define __os_close_mach_recv __os_cleanup_unsupported +#define __os_release_mach_send __os_cleanup_unsupported +#define __os_preserve_errno __os_cleanup_unsupported +#define __os_release __os_cleanup_unsupported +#define __os_cfrelease __os_cleanup_unsupported +#define __os_iorelease __os_cleanup_unsupported +#define __os_ioclose __os_cleanup_unsupported +#define __os_unfair_unlock __os_cleanup_unsupported #endif // __has_attribute(cleanup) __END_DECLS;