summaryrefslogtreecommitdiff
path: root/src/vm/fusionsink.cpp
blob: b40192b68af86e53f06a09f89937bc1818fa754f (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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

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


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

#include "common.h"

#include <stdlib.h>
#include "fusionsink.h"
#include "ex.h"

STDMETHODIMP FusionSink::QueryInterface(REFIID riid, void** ppv)
{
    CONTRACTL
    {
        MODE_ANY;
        GC_NOTRIGGER;
        NOTHROW;
        ENTRY_POINT;
    }
    CONTRACTL_END;

    HRESULT hr = S_OK;

    BEGIN_ENTRYPOINT_NOTHROW;
    
    *ppv = NULL;

    if (riid == IID_IUnknown)
        *ppv = (IUnknown*) (IAssemblyBindSink*) this;
    else if (riid == IID_IAssemblyBindSink)   
        *ppv = (IAssemblyBindSink*)this;
    else if (riid == IID_INativeImageEvaluate)   
        *ppv = (INativeImageEvaluate*)this;
    if (*ppv == NULL)
        hr = E_NOINTERFACE;
    else
        AddRef();   

    END_ENTRYPOINT_NOTHROW;

    return hr;
}

STDMETHODIMP FusionSink::OnProgress(DWORD dwNotification,
                                    HRESULT hrNotification,
                                    LPCWSTR szNotification,
                                    DWORD dwProgress,
                                    DWORD dwProgressMax,
                                    LPVOID pvBindInfo,
                                    IUnknown* punk)
{
    LIMITED_METHOD_CONTRACT;
    HRESULT hr = S_OK;
    switch(dwNotification) {
    case ASM_NOTIFICATION_DONE:
        m_LastResult = hrNotification;
        if(m_pAbortUnk) {
            m_pAbortUnk->Release();
            m_pAbortUnk = NULL;
        }

        if(punk && SUCCEEDED(hrNotification))
            hr = punk->QueryInterface(IID_IUnknown, (void**) &m_punk);
        m_hEvent->Set();
        break;
    case ASM_NOTIFICATION_NATIVE_IMAGE_DONE:
        if(punk && SUCCEEDED(hrNotification))
            hr = punk->QueryInterface(IID_IUnknown, (void**) &m_pNIunk);
        break;
        
    case ASM_NOTIFICATION_START:
        if(punk)
            hr = punk->QueryInterface(IID_IUnknown, (void**) &m_pAbortUnk);
        break;

    case ASM_NOTIFICATION_ATTEMPT_NEXT_CODEBASE:
        break;

    case ASM_NOTIFICATION_BIND_INFO:
        FusionBindInfo          *pBindInfo;

        pBindInfo = (FusionBindInfo *)pvBindInfo;

        if (pBindInfo && m_pFusionLog == NULL) {
            m_pFusionLog = pBindInfo->pdbglog;
            if (m_pFusionLog) {
                m_pFusionLog->AddRef();
            }
        }
        break;
    default:
        break;
    }
    
    return hr;
}

ULONG FusionSink::AddRef()
{
    LIMITED_METHOD_CONTRACT;
    ULONG cRefCount = 0;
    //BEGIN_ENTRYPOINT_VOIDRET;

    cRefCount = (InterlockedIncrement(&m_cRef));
    //END_ENTRYPOINT_VOIDRET;
    return cRefCount;
}

ULONG FusionSink::Release()
{
    WRAPPER_NO_CONTRACT;
    STATIC_CONTRACT_ENTRY_POINT;
    BEGIN_CLEANUP_ENTRYPOINT;
    
    ULONG   cRef = InterlockedDecrement(&m_cRef);
    if (!cRef) {
        Reset();
        delete this;
    }
    END_CLEANUP_ENTRYPOINT;
    return (cRef);
}

HRESULT FusionSink::AssemblyResetEvent()
{
    WRAPPER_NO_CONTRACT;
    HRESULT hr = AssemblyCreateEvent();
    if(FAILED(hr)) return hr;

    if(!m_hEvent->Reset()) {
        hr = HRESULT_FROM_GetLastErrorNA();
    }

    return hr;
}

HRESULT FusionSink::AssemblyCreateEvent()
{
    STATIC_CONTRACT_NOTHROW;
    HRESULT hr = S_OK;
    if(m_hEvent == NULL) {
        // Initialize the event to require manual reset
        // and to initially signaled.
        EX_TRY {
            m_hEvent = new Event();
            m_hEvent->CreateManualEvent(TRUE);
        }
        EX_CATCH
        {
            hr = GET_EXCEPTION()->GetHR();
        }
        EX_END_CATCH(SwallowAllExceptions);
    }
    return hr;
}

HRESULT FusionSink::Wait()
{
    STATIC_CONTRACT_NOTHROW;

#if CHECK_INVARIANTS
    _ASSERTE(CheckPointer(this));
    _ASSERTE(CheckPointer(m_hEvent));
#endif  // CHECK_INVARIANTS

    HRESULT hr = S_OK;
    DWORD   dwReturn = 0;

    // CLREvent::Wait will switch mode if needed;

    // Waiting for a signal from fusion - which we are guaranteed to get.
    // We do a WaitForMultipleObjects (STA and MTA) and pump messages in the STA case
    // in the call so we shouldn't freeze the system.
    EX_TRY 
    {
        dwReturn = m_hEvent->Wait(INFINITE,TRUE);
    } 
    EX_CATCH 
    {
        // Fusion uses us via COM interface so we need to swallow exceptions
        hr = GET_EXCEPTION()->GetHR();

        //@todo: is it right thing to do to swallow exceptions here
    } 
    EX_END_CATCH(SwallowAllExceptions);

    return hr;
}

HRESULT FusionSink::Evaluate (
        IAssembly *pILAssembly, 
        IAssembly *pNativeAssembly,
        BYTE * pbCachedData,
        DWORD dwDataSize
        )
{
    LIMITED_METHOD_CONTRACT;
    STATIC_CONTRACT_ENTRY_POINT;

    return S_OK;
}