File: ActivityIdHelper.cs

package info (click to toggle)
mono 6.8.0.105%2Bdfsg-3.3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,284,512 kB
  • sloc: cs: 11,172,132; xml: 2,850,069; ansic: 671,653; cpp: 122,091; perl: 59,366; javascript: 30,841; asm: 22,168; makefile: 20,093; sh: 15,020; python: 4,827; pascal: 925; sql: 859; sed: 16; php: 1
file content (95 lines) | stat: -rw-r--r-- 4,753 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//------------------------------------------------------------------------------
// <copyright file="ActivityIdHelper.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------

namespace System.Web.Util {
    using System;
    using System.Diagnostics.Tracing;
    using System.Runtime.CompilerServices;
    using System.Threading;

    internal sealed class ActivityIdHelper {

        private delegate Guid GetCurrentDelegate();
        private delegate void SetAndDestroyDelegate(Guid activityId);
        private delegate void SetAndPreserveDelegate(Guid activityId, out Guid oldActivityThatWillContinue);

        // Note to callers: this field can be null.
        internal static readonly ActivityIdHelper Instance = GetSingleton();

        private static readonly Guid _baseGuid = Guid.NewGuid();
        private static long _counter;

        private readonly GetCurrentDelegate _getCurrentDel;
        private readonly SetAndDestroyDelegate _setAndDestroyDel;
        private readonly SetAndPreserveDelegate _setAndPreserveDel;

        // use the factory to create an instance of this type
        private ActivityIdHelper(GetCurrentDelegate getCurrentDel, SetAndDestroyDelegate setAndDestroyDel, SetAndPreserveDelegate setAndPreserveDel) {
            _getCurrentDel = getCurrentDel;
            _setAndDestroyDel = setAndDestroyDel;
            _setAndPreserveDel = setAndPreserveDel;
        }

        // Gets the current thread's activity ID.
        public Guid CurrentThreadActivityId {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get { return _getCurrentDel(); }
        }

        private static ActivityIdHelper GetSingleton() {
            try {
                // The mscorlib APIs we depend on weren't added until Blue, so we can't
                // take a direct dependency. Need to light up instead.

                var getCurrentDel = (GetCurrentDelegate)Delegate.CreateDelegate(
                    typeof(GetCurrentDelegate), typeof(EventSource), "get_CurrentThreadActivityId", ignoreCase: false, throwOnBindFailure: false);

                var setAndDestroyDel = (SetAndDestroyDelegate)Delegate.CreateDelegate(
                    typeof(SetAndDestroyDelegate), typeof(EventSource), "SetCurrentThreadActivityId", ignoreCase: false, throwOnBindFailure: false);

                var setAndPreserveDel = (SetAndPreserveDelegate)Delegate.CreateDelegate(
                    typeof(SetAndPreserveDelegate), typeof(EventSource), "SetCurrentThreadActivityId", ignoreCase: false, throwOnBindFailure: false);

                if (getCurrentDel != null && setAndDestroyDel != null && setAndPreserveDel != null) {
                    return new ActivityIdHelper(getCurrentDel, setAndDestroyDel, setAndPreserveDel);
                }
            }
            catch {
                // exceptions are not fatal; we just won't be able to call the new APIs
            }

            return null;
        }

        // Disposes of the thread's existing activity ID, then sets the new activity ID on this thread.
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void SetCurrentThreadActivityId(Guid activityId) {
            _setAndDestroyDel(activityId);
        }

        // Suspends (but does not dispose of) the thread's existing activity ID, then sets a new activity ID on this thread.
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void SetCurrentThreadActivityId(Guid activityId, out Guid oldActivityThatWillContinue) {
            _setAndPreserveDel(activityId, out oldActivityThatWillContinue);
        }

        // !! SECURITY WARNING !!
        // The GUIDs created by this method are predictable and should be used ONLY for tracing.
        // Any other use (such as leaking them to the user) constitutes information disclosure.
        //
        // This is a perf-sensitive method since it could potentially be called many times per
        // request. Guid.NewGuid() is slow since it eventually calls CAPI, and we did actually
        // see it show up as a bottleneck when developing MVC 2. The below implementation has
        // measurably better performance characteristics than calling the other Guid ctors.
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe Guid UnsafeCreateNewActivityId() {
            Guid guidCopy = _baseGuid;
            *(long*)(&guidCopy) ^= Interlocked.Increment(ref _counter); // operate on the copy, not the original
            return guidCopy;
        }

    }
}