Advertisement
Guest User

Untitled

a guest
Sep 20th, 2017
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.14 KB | None | 0 0
  1. //
  2. // Activity.swift
  3. //
  4. // Created by Zachary Waldowski on 8/21/16.
  5. // Copyright © 2016 Zachary Waldowski. Licensed under MIT.
  6. //
  7.  
  8. import os.activity
  9.  
  10. private final class LegacyActivityContext {
  11. let dsoHandle: UnsafeRawPointer?
  12. let description: UnsafePointer<CChar>
  13. let flags: os_activity_flag_t
  14.  
  15. init(dsoHandle: UnsafeRawPointer?, description: UnsafePointer<CChar>, flags: os_activity_flag_t) {
  16. self.dsoHandle = dsoHandle
  17. self.description = description
  18. self.flags = flags
  19. }
  20. }
  21.  
  22. @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
  23. @_silgen_name("_os_activity_create") private func _os_activity_create(_ dso: UnsafeRawPointer?, _ description: UnsafePointer<Int8>, _ parent : Unmanaged<AnyObject>?, _ flags: os_activity_flag_t) -> AnyObject!
  24.  
  25. @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
  26. @_silgen_name("os_activity_apply") private func _os_activity_apply(_ storage: AnyObject, _ block: @convention(block) () -> ())
  27.  
  28. @_silgen_name("_os_activity_initiate") private func __os_activity_initiate(_ dso: UnsafeRawPointer?, _ description: UnsafePointer<Int8>, _ flags: os_activity_flag_t, _ block: @convention(block) () -> ())
  29.  
  30. @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
  31. @_silgen_name("os_activity_scope_enter") private func _os_activity_scope_enter(_ storage: AnyObject, _ state: UnsafeMutablePointer<os_activity_scope_state_s>)
  32.  
  33. @_silgen_name("_os_activity_start") private func __os_activity_start(_ dso: UnsafeRawPointer?, _ description: UnsafePointer<Int8>, _ flags: os_activity_flag_t) -> UInt64
  34.  
  35. @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
  36. @_silgen_name("os_activity_scope_leave") private func _os_activity_scope_leave(_ state: UnsafeMutablePointer<os_activity_scope_state_s>)
  37.  
  38. @_silgen_name("os_activity_end") private func __os_activity_end(_ state: UInt64)
  39.  
  40. @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
  41. private let OS_ACTIVITY_NONE = unsafeBitCast(dlsym(UnsafeMutableRawPointer(bitPattern: -2), "_os_activity_none"), to: Unmanaged<AnyObject>.self)
  42.  
  43. @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
  44. private let OS_ACTIVITY_CURRENT = unsafeBitCast(dlsym(UnsafeMutableRawPointer(bitPattern: -2), "_os_activity_current"), to: Unmanaged<AnyObject>.self)
  45.  
  46. public struct Activity {
  47.  
  48. /// Support flags for OSActivity.
  49. public struct Options: OptionSet {
  50. public let rawValue: UInt32
  51. public init(rawValue: UInt32) {
  52. self.rawValue = rawValue
  53. }
  54.  
  55. /// Detach a newly created activity from a parent activity, if any.
  56. ///
  57. /// If passed in conjunction with a parent activity, the activity will
  58. /// only note what activity "created" the new one, but will make the
  59. /// new activity a top level activity. This allows seeing what
  60. /// activity triggered work without actually relating the activities.
  61. public static let detached = Options(rawValue: OS_ACTIVITY_FLAG_DETACHED.rawValue)
  62. /// Will only create a new activity if none present.
  63. ///
  64. /// If an activity ID is already present, a new activity will be
  65. /// returned with the same underlying activity ID.
  66. @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
  67. public static let ifNonePresent = Options(rawValue: OS_ACTIVITY_FLAG_IF_NONE_PRESENT.rawValue)
  68. }
  69.  
  70. private let opaque: AnyObject
  71.  
  72. /// Creates an activity.
  73. public init(_ description: StaticString, dso: UnsafeRawPointer? = #dsohandle, options: Options = []) {
  74. self.opaque = description.withUTF8Buffer { (buf: UnsafeBufferPointer<UInt8>) -> AnyObject in
  75. let str = buf.baseAddress!.withMemoryRebound(to: Int8.self, capacity: 8, { $0 })
  76. let flags = os_activity_flag_t(rawValue: options.rawValue)
  77. if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *), OS_ACTIVITY_OBJECT_API != 0 {
  78. return _os_activity_create(dso, str, OS_ACTIVITY_CURRENT, flags)
  79. } else {
  80. return LegacyActivityContext(dsoHandle: dso, description: str, flags: flags)
  81. }
  82. }
  83. }
  84.  
  85. private func active(execute body: @convention(block) () -> ()) {
  86. if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *), OS_ACTIVITY_OBJECT_API != 0 {
  87. _os_activity_apply(opaque, body)
  88. } else {
  89. let context = opaque as! LegacyActivityContext
  90. __os_activity_initiate(context.dsoHandle, context.description, context.flags, body)
  91. }
  92. }
  93.  
  94. /// Executes a function body within the context of the activity.
  95. public func active<Return>(execute body: () throws -> Return) rethrows -> Return {
  96. func impl(execute work: () throws -> Return, recover: (Error) throws -> Return) rethrows -> Return {
  97. var result: Return?
  98. var error: Error?
  99. active {
  100. do {
  101. result = try work()
  102. } catch let e {
  103. error = e
  104. }
  105. }
  106. if let e = error {
  107. return try recover(e)
  108. } else {
  109. return result!
  110. }
  111.  
  112. }
  113.  
  114. return try impl(execute: body, recover: { throw $0 })
  115. }
  116.  
  117. /// Opaque structure created by `Activity.enter()` and restored using
  118. /// `leave()`.
  119. public struct Scope {
  120. fileprivate var state = os_activity_scope_state_s()
  121. fileprivate init() {}
  122.  
  123. /// Pops activity state to `self`.
  124. public mutating func leave() {
  125. if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *), OS_ACTIVITY_OBJECT_API != 0 {
  126. _os_activity_scope_leave(&state)
  127. } else {
  128. UnsafeRawPointer(bitPattern: Int(state.opaque.0)).map(Unmanaged<AnyObject>.fromOpaque)?.release()
  129. __os_activity_end(state.opaque.1)
  130. }
  131.  
  132. }
  133. }
  134.  
  135. /// Changes the current execution context to the activity.
  136. ///
  137. /// An activity can be created and applied to the current scope by doing:
  138. ///
  139. /// var scope = OSActivity("my new activity").enter()
  140. /// defer { scope.leave() }
  141. /// ... do some work ...
  142. ///
  143. public func enter() -> Scope {
  144. var scope = Scope()
  145. if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *), OS_ACTIVITY_OBJECT_API != 0 {
  146. _os_activity_scope_enter(opaque, &scope.state)
  147. } else {
  148. let context = opaque as! LegacyActivityContext
  149. scope.state.opaque.0 = numericCast(Int(bitPattern: Unmanaged.passRetained(context).toOpaque()))
  150. scope.state.opaque.1 = __os_activity_start(context.dsoHandle, context.description, context.flags)
  151. }
  152. return scope
  153. }
  154.  
  155. /// Creates an activity.
  156. @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
  157. public init(_ description: StaticString, dso: UnsafeRawPointer? = #dsohandle, parent: Activity, options: Options = []) {
  158. self.opaque = description.withUTF8Buffer { (buf: UnsafeBufferPointer<UInt8>) -> AnyObject in
  159. let str = buf.baseAddress!.withMemoryRebound(to: Int8.self, capacity: 8, { $0 })
  160. let flags = os_activity_flag_t(rawValue: options.rawValue)
  161. return _os_activity_create(dso, str, Unmanaged.passRetained(parent.opaque), flags)
  162. }
  163. }
  164.  
  165. private init(_ opaque: AnyObject) {
  166. self.opaque = opaque
  167. }
  168.  
  169. /// An activity with no traits; as a parent, it is equivalent to a
  170. /// detached activity.
  171. @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
  172. public static var none: Activity {
  173. return Activity(OS_ACTIVITY_NONE.takeUnretainedValue())
  174. }
  175.  
  176. /// The running activity.
  177. ///
  178. /// As a parent, the new activity is linked to the current activity, if one
  179. /// is present. If no activity is present, it behaves the same as `.none`.
  180. @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
  181. public static var current: Activity {
  182. return Activity(OS_ACTIVITY_CURRENT.takeUnretainedValue())
  183. }
  184.  
  185. /// Label an activity auto-generated by UI with a name that is useful for
  186. /// debugging macro-level user actions.
  187. ///
  188. /// This function should be called early within the scope of an `IBAction`,
  189. /// before any sub-activities are created. The name provided will be shown
  190. /// in tools in addition to the system-provided name. This API should only
  191. /// be called once, and only on an activity created by the system. These
  192. /// actions help determine workflow of the user in order to reproduce
  193. /// problems that occur.
  194. ///
  195. /// For example, a control press and/or menu item selection can be labeled:
  196. ///
  197. /// OSActivity.labelUserAction("New mail message")
  198. /// OSActivity.labelUserAction("Empty trash")
  199. ///
  200. /// Where the underlying name will be "gesture:" or "menuSelect:".
  201. @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
  202. public static func labelUserAction(_ description: StaticString, dso: UnsafeRawPointer? = #dsohandle) {
  203. description.withUTF8Buffer { (buf: UnsafeBufferPointer<UInt8>) in
  204. let str = buf.baseAddress!.withMemoryRebound(to: Int8.self, capacity: 8, { $0 })
  205. _os_activity_label_useraction(UnsafeMutableRawPointer(mutating: dso!), str)
  206. }
  207. }
  208.  
  209. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement