#include <os/api.h>
#include <os/assumes.h>
#include <os/object_private.h>
+#include <os/lock.h>
#include <sys/errno.h>
#include <sys/cdefs.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
+#include <dirent.h>
#include <mach/mach_init.h>
#include <mach/port.h>
#include <mach/mach_port.h>
#include <mach/kern_return.h>
+#include <mach/mach_right.h>
+
+#if DARWIN_TAPI
+#include "tapi.h"
+#endif
__BEGIN_DECLS;
* @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.
*/
}
}
+/*!
+ * @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)))
__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)))
__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);
}
/*!
* 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)
}
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
* 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
}
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;