summaryrefslogtreecommitdiff
path: root/src/vm/assemblysink.cpp
blob: 82d02c85720e5088337ecd4c72e1497100997ad0 (plain)
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

/*============================================================
**
** Header:  AssemblySink.cpp
**
** Purpose: Implements AssemblySink, event objects that block
**          the current thread waiting for an asynchronous load
**          of an assembly to succeed.
**
**


**
===========================================================*/

#include "common.h"
#ifdef FEATURE_FUSION
#include <stdlib.h>
#include "assemblysink.h"
#include "assemblyspec.hpp"
#include "corpriv.h"
#include "appdomain.inl"

AssemblySink::AssemblySink(AppDomain* pDomain) 
{
    WRAPPER_NO_CONTRACT;
    m_Domain=pDomain->GetId();
    m_pSpec=NULL;
    m_CheckCodebase = FALSE;
}

void AssemblySink::Reset()
{
    CONTRACTL
    {
        INSTANCE_CHECK;
        NOTHROW;
        GC_TRIGGERS;
        MODE_ANY;
    }
    CONTRACTL_END;

    m_CheckCodebase = FALSE;
    FusionSink::Reset();
}

ULONG AssemblySink::Release()
{
    CONTRACTL
    {
        INSTANCE_CHECK;
        NOTHROW;
        if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);}
        MODE_ANY;
        PRECONDITION(CheckPointer(this));
    } CONTRACTL_END;
    
    
    ULONG   cRef = InterlockedDecrement(&m_cRef);
    if (!cRef) {
        Reset();
        AssemblySink* ret = this;
        // If we have a domain we keep a pool of one around. If we get an entry
        // back from the pool then we were not added to the pool and need to be deleted.
        // If we do not have a pool then we need to delete it.
        
        


        // TODO: SetupThread may throw.  What do we do with Release?
        HRESULT hr = S_OK;
        SetupThreadNoThrow(&hr);
        {
            GCX_COOP();
        
            if(m_Domain.m_dwId) {
                AppDomainFromIDHolder AD(m_Domain, TRUE);
                if (!AD.IsUnloaded())
                     ret = FastInterlockCompareExchangePointer(&(AD->m_pAsyncPool),
                                                               this,
                                                               NULL);

            }
        }

        if(ret != NULL) 
            delete this;
    }
    return (cRef);
}



STDMETHODIMP AssemblySink::OnProgress(DWORD dwNotification,
                                      HRESULT hrNotification,
                                      LPCWSTR szNotification,
                                      DWORD dwProgress,
                                      DWORD dwProgressMax,
                                      LPVOID pvBindInfo,
                                      IUnknown* punk)
{
    STATIC_CONTRACT_NOTHROW;

    HRESULT hr = S_OK;

    switch(dwNotification) {

    case ASM_NOTIFICATION_BIND_INFO:
        FusionBindInfo          *pBindInfo;

        pBindInfo = (FusionBindInfo *)pvBindInfo;

        if (pBindInfo && pBindInfo->pNamePolicy && m_pSpec) {
            pBindInfo->pNamePolicy->AddRef();
            m_pSpec->SetNameAfterPolicy(pBindInfo->pNamePolicy);
        }
        break;

    default:
        break;
    }

    if (SUCCEEDED(hr))
        hr = FusionSink::OnProgress(dwNotification, hrNotification, szNotification, 
                                    dwProgress, dwProgressMax, pvBindInfo, punk);

    return hr;
}


HRESULT AssemblySink::Wait()
{
    STATIC_CONTRACT_NOTHROW;

    HRESULT hr = FusionSink::Wait();

    if (FAILED(hr)) {
        // If we get an exception then we will just release this sink. It may be the
        // case that the appdomain was terminated. Other exceptions will cause the
        // sink to be scavenged but this is ok. A new one will be generated for the
        // next bind.
        m_Domain.m_dwId = 0;
        // The AssemblySpec passed is stack allocated in some cases.
        // Remove reference to it to prevent AV in delayed fusion bind notifications.
        m_pSpec = NULL;
    }

    return hr;
}
#endif