ReactOS 0.4.15-dev-7834-g00c4b3d
udf_dbg.cpp
Go to the documentation of this file.
1
2// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3// All rights reserved
4// This file was released under the GPLv2 on June 2015.
6#include "udffs.h"
7#if defined(UDF_DBG) || defined(PRINT_ALWAYS)
8
9//#define TRACK_RESOURCES
10//#define TRACK_REF_COUNTERS
11
12ULONG ResCounter = 0;
13ULONG AcqCounter = 0;
14ULONG UdfTimeStamp = -1;
15
20 ULONG BugCheckId,
22) {
24#ifdef TRACK_RESOURCES
25 UDFPrint(("Res:Sha:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
26 BugCheckId,Line,PsGetCurrentThread()));
27#endif
28
30
31#ifdef USE_DLD
32
33 if (Wait) {
34 DLDAcquireShared(Resource, BugCheckId, Line,FALSE);
35 Success = TRUE;
36 } else {
38 }
39
40#else
41
43
44#endif // USE_DLD
45
46 if(Success) {
47#ifdef TRACK_RESOURCES
48 UDFPrint(("Res:Sha:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
49 BugCheckId,Line,PsGetCurrentThread()));
50#endif
51 AcqCounter++;
52 return Success;
53 }
54#ifdef TRACK_RESOURCES
55 UDFPrint(("Res:Sha:Fail:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
56 BugCheckId,Line,PsGetCurrentThread()));
57#endif
58 return FALSE;
59}
60
65 ULONG BugCheckId,
67) {
69#ifdef TRACK_RESOURCES
70 UDFPrint(("Res:Sha*:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
71 BugCheckId,Line,PsGetCurrentThread()));
72#endif
73
75
76#ifdef USE_DLD
77
78 if (Wait) {
79 DLDAcquireShared(Resource, BugCheckId, Line,FALSE);
80 Success = TRUE;
81 } else {
83 }
84
85#else
86
88
89#endif // USE_DLD
90
91 if(Success) {
92#ifdef TRACK_RESOURCES
93 UDFPrint(("Res:Sha*:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
94 BugCheckId,Line,PsGetCurrentThread()));
95#endif
96 AcqCounter++;
97 return Success;
98 }
99#ifdef TRACK_RESOURCES
100 UDFPrint(("Res:Sha*:Fail:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
101 BugCheckId,Line,PsGetCurrentThread()));
102#endif
103 return FALSE;
104}
105
110 ULONG BugCheckId,
111 ULONG Line
112) {
114#ifdef TRACK_RESOURCES
115 UDFPrint(("Res:Exc:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
116 BugCheckId,Line,PsGetCurrentThread()));
117#endif
118
119
121
122#ifdef USE_DLD
123
124 if (Wait) {
125 DLDAcquireExclusive(Resource, BugCheckId, Line);
126 Success = TRUE;
127 } else {
129 }
130
131#else
132
134
135#endif // USE_DLD
136
137
138
139 if(Success) {
140#ifdef TRACK_RESOURCES
141 UDFPrint(("Res:Exc:OK:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
142 BugCheckId,Line,PsGetCurrentThread()));
143#endif
144 AcqCounter++;
145 return Success;
146 }
147#ifdef TRACK_RESOURCES
148 UDFPrint(("Res:Exc:Fail:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
149 BugCheckId,Line,PsGetCurrentThread()));
150#endif
151// BrutePoint();
152 return FALSE;
153
154}
155
156VOID
160 ULONG BugCheckId,
161 ULONG Line
162 )
163{
165#ifdef TRACK_RESOURCES
166 UDFPrint(("Res:Free:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
167 BugCheckId,Line,PsGetCurrentThread()));
168#endif
170#ifdef TRACK_RESOURCES
171 UDFPrint(("Res:Free:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
172 BugCheckId,Line,ResourceThreadId));
173#endif
174 AcqCounter--;
175}
176
177VOID
181 ULONG BugCheckId,
182 ULONG Line
183 )
184{
186#ifdef TRACK_RESOURCES
187 UDFPrint(("Res:Del:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
188 BugCheckId,Line,ResourceThreadId));
189#endif
190 _SEH2_TRY {
191 ASSERT((*((PULONG)Resource)));
192 ASSERT((*(((PULONG)Resource)+1)));
196 BrutePoint();
197 } _SEH2_END;
198#ifdef TRACK_RESOURCES
199 UDFPrint(("Res:Del:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
200 BugCheckId,Line,ResourceThreadId));
201#endif
202 ResCounter--;
203}
204
209 ULONG BugCheckId,
210 ULONG Line
211 )
212{
214 NTSTATUS RC;
215#ifdef TRACK_RESOURCES
216 UDFPrint(("Res:Ini:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
217 BugCheckId,Line,ResourceThreadId));
218#endif
219 ASSERT(!(*((PULONG)Resource)));
220 ASSERT(!(*(((PULONG)Resource)+1)));
222#ifdef TRACK_RESOURCES
223 UDFPrint(("Res:Ini:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
224 BugCheckId,Line,ResourceThreadId));
225#endif
226 if(NT_SUCCESS(RC)) {
227 ResCounter++;
228 }
229 return RC;
230}
231
232VOID
236 ULONG BugCheckId,
237 ULONG Line
238 )
239{
241#ifdef TRACK_RESOURCES
242 UDFPrint(("Res:2Sha:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
243 BugCheckId,Line,ResourceThreadId));
244#endif
246#ifdef TRACK_RESOURCES
247 UDFPrint(("Res:2Sha:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
248 BugCheckId,Line,ResourceThreadId));
249#endif
250}
251
256 ULONG BugCheckId,
257 ULONG Line
258) {
260#ifdef TRACK_RESOURCES
261 UDFPrint(("Res:Sha*:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
262 BugCheckId,Line,PsGetCurrentThread()));
263#endif
264
266
267#ifdef USE_DLD
268
269 if (Wait) {
270 DLDAcquireShared(Resource, BugCheckId, Line,TRUE);
271 Success = TRUE;
272 } else {
274 }
275
276#else
277
279
280#endif // USE_DLD
281
282
283 if(Success) {
284#ifdef TRACK_RESOURCES
285 UDFPrint(("Res:Sha*:OK:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
286 BugCheckId,Line,PsGetCurrentThread()));
287#endif
288 return Success;
289 }
290#ifdef TRACK_RESOURCES
291 UDFPrint(("Res:Sha*:Fail:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource,
292 BugCheckId,Line,PsGetCurrentThread()));
293#endif
294// BrutePoint();
295 return FALSE;
296
297}
298
299
300LONG
302 IN PLONG addr,
303 ULONG BugCheckId,
304 ULONG Line)
305{
306#ifdef TRACK_REF_COUNTERS
307 LONG a;
309 UDFPrint(("ThId:%x:Ilck:Inc:FileId:%x:Line:%d:Ref:%x:Val:%x:%x\n",
310 PsGetCurrentThread(),BugCheckId,Line,addr,a-1,a));
311 return a;
312#else
314#endif
315}
316
317LONG
319 IN PLONG addr,
320 ULONG BugCheckId,
321 ULONG Line)
322{
323#ifdef TRACK_REF_COUNTERS
324 LONG a;
326 UDFPrint(("ThId:%x:Ilck:Dec:FileId:%x:Line:%d:Ref:%x:Val:%x:%x\n",
327 PsGetCurrentThread(),BugCheckId,Line,addr,a+1,a));
328 return a;
329#else
331#endif
332}
333
334LONG
336 IN PLONG addr,
337 IN LONG i,
338 ULONG BugCheckId,
339 ULONG Line)
340{
341#ifdef TRACK_REF_COUNTERS
342 LONG a;
344 UDFPrint(("ThId:%x:Ilck:Add:FileId:%x:Line:%d:Ref:%x:Val:%x:%x\n",
345 PsGetCurrentThread(),BugCheckId,Line,addr,a,a+i));
346 return a;
347#else
349#endif
350}
351
352#define MAX_MEM_DEBUG_DESCRIPTORS 8192
353
354typedef struct _MEM_DESC {
356 PCHAR Addr;
357#ifdef TRACK_SYS_ALLOC_CALLERS
358 ULONG SrcId;
359 ULONG SrcLine;
360#endif //TRACK_SYS_ALLOC_CALLERS
362} MEM_DESC, *PMEM_DESC;
363
364
365MEM_DESC MemDesc[MAX_MEM_DEBUG_DESCRIPTORS];
366ULONG cur_max = 0;
367ULONG AllocCountPaged = 0;
368ULONG AllocCountNPaged = 0;
369ULONG MemDescInited = 0;
370
371PVOID
372DebugAllocatePool(
374 ULONG size
375#ifdef TRACK_SYS_ALLOC_CALLERS
376 , ULONG SrcId,
377 ULONG SrcLine
378#endif //TRACK_SYS_ALLOC_CALLERS
379) {
380 ULONG i;
381// UDFPrint(("SysAllocated: %x\n",AllocCount));
382 if(!MemDescInited) {
383 RtlZeroMemory(&MemDesc, sizeof(MemDesc));
384 MemDescInited = 1;
385 }
386 for (i=0;i<cur_max;i++) {
387 if (MemDesc[i].Addr==NULL) {
388 MemDesc[i].Addr = (PCHAR)ExAllocatePoolWithTag(Type, (size), 'Fnwd'); // dwnF
389
390 ASSERT(MemDesc[i].Addr);
391
392 if(MemDesc[i].Addr) {
393 if(Type == PagedPool) {
394 AllocCountPaged += (size+7) & ~7;
395 } else {
396 AllocCountNPaged += (size+7) & ~7;
397 }
398 }
399
400 MemDesc[i].Length = size;
401 MemDesc[i].Type = Type;
402#ifdef TRACK_SYS_ALLOC_CALLERS
403 MemDesc[i].SrcId = SrcId;
404 MemDesc[i].SrcLine = SrcLine;
405#endif //TRACK_SYS_ALLOC_CALLERS
406 return MemDesc[i].Addr;
407 }
408 }
409 if(cur_max == MAX_MEM_DEBUG_DESCRIPTORS) {
410 UDFPrint(("Debug memory descriptor list full\n"));
411 return ExAllocatePoolWithTag(Type, (size) , 'Fnwd');
412 }
413
414 MemDesc[i].Addr = (PCHAR)ExAllocatePoolWithTag(Type, (size) , 'Fnwd');
415
416 if(MemDesc[i].Addr) {
417 if(Type == PagedPool) {
418 AllocCountPaged += (size+7) & ~7;
419 } else {
420 AllocCountNPaged += (size+7) & ~7;
421 }
422 }
423
424 MemDesc[i].Length = (size);
425#ifdef TRACK_SYS_ALLOC_CALLERS
426 MemDesc[i].SrcId = SrcId;
427 MemDesc[i].SrcLine = SrcLine;
428#endif //TRACK_SYS_ALLOC_CALLERS
429 MemDesc[i].Type = Type;
430 cur_max++;
431 return MemDesc[cur_max-1].Addr;
432
433}
434
435VOID DebugFreePool(PVOID addr) {
436 ULONG i;
437
438 ASSERT(addr);
439
440 for (i=0;i<cur_max;i++) {
441 if (MemDesc[i].Addr == addr) {
442
443 if(MemDesc[i].Type == PagedPool) {
444 AllocCountPaged -= (MemDesc[i].Length+7) & ~7;
445 } else {
446 AllocCountNPaged -= (MemDesc[i].Length+7) & ~7;
447 }
448
449 MemDesc[i].Addr = NULL;
450 MemDesc[i].Length = 0;
451#ifdef TRACK_SYS_ALLOC_CALLERS
452 MemDesc[i].SrcId = 0;
453 MemDesc[i].SrcLine = 0;
454#endif //TRACK_SYS_ALLOC_CALLERS
455 goto not_bug;
456 }
457 }
458 if (i==cur_max && cur_max != MAX_MEM_DEBUG_DESCRIPTORS) {
459 UDFPrint(("Buug! - Deallocating nonallocated block\n"));
460 return;
461 }
462not_bug:
463// UDFPrint(("SysAllocated: %x\n",AllocCount));
465}
466
468UDFWaitForSingleObject(
471 )
472{
473 UDFPrint(("UDFWaitForSingleObject\n"));
474 LARGE_INTEGER LocalTimeout;
475 LARGE_INTEGER delay;
477
478 if(Timeout && (Timeout->QuadPart)) LocalTimeout = *Timeout;
479 else LocalTimeout.QuadPart = 0x7FFFFFFFFFFFFFFFLL;
480
481 UDFPrint(("SignalState %x\n", *Object));
483 if((*Object)) return STATUS_SUCCESS;
484 while(LocalTimeout.QuadPart>0 && !(*Object) ) {
485 UDFPrint(("SignalState %x\n", *Object));
486 // Stall for a while.
488 LocalTimeout.QuadPart -= WAIT_FOR_XXX_EMU_DELAY;
489 }
490 return STATUS_SUCCESS;
491} // end UDFWaitForSingleObject()
492
497 )
498{
500 LARGE_INTEGER dto;
501// LARGE_INTEGER cto;
502 NTSTATUS RC;
503 ULONG c = 20;
504
505 dto.QuadPart = -5LL*1000000LL*10LL; // 5 sec
506// cto.QuadPart = Timeout->QuadPart;
507 if(Timeout) {
508 if(dto.QuadPart > Timeout->QuadPart) {
509 to = Timeout;
510 } else {
511 to = &dto;
512 }
513 } else {
514 to = &dto;
515 }
516
517 for(; c--; c) {
519 if(RC == STATUS_SUCCESS)
520 break;
521 UDFPrint(("No response ?\n"));
522 if(c<2)
523 BrutePoint();
524 }
525 return RC;
526}
527#endif // UDF_DBG
unsigned char BOOLEAN
Type
Definition: Type.h:7
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
LONG NTSTATUS
Definition: precomp.h:26
_Acquires_exclusive_lock_ Resource _Acquires_shared_lock_ Resource _Inout_ PERESOURCE Resource
Definition: cdprocs.h:843
VOID DLDAcquireShared(PERESOURCE Resource, ULONG BugCheckId, ULONG Line, BOOLEAN WaitForExclusive)
Definition: dldetect.cpp:398
VOID DLDAcquireExclusive(PERESOURCE Resource, ULONG BugCheckId, ULONG Line)
Definition: dldetect.cpp:313
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define ExReleaseResourceForThreadLite(res, thrdID)
Definition: env_spec_w32.h:635
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
NTSTATUS ExInitializeResourceLite(PULONG res)
Definition: env_spec_w32.h:641
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define ExConvertExclusiveToSharedLite(res)
Definition: env_spec_w32.h:652
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define ExAcquireResourceExclusiveLite(res, wait)
Definition: env_spec_w32.h:615
ERESOURCE * PERESOURCE
Definition: env_spec_w32.h:595
#define ExDeleteResourceLite(res)
Definition: env_spec_w32.h:647
ULONG ERESOURCE
Definition: env_spec_w32.h:594
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define KeDelayExecutionThread(mode, foo, t)
Definition: env_spec_w32.h:484
#define BrutePoint()
Definition: env_spec_w32.h:504
#define ExAcquireResourceSharedLite(res, wait)
Definition: env_spec_w32.h:621
#define PagedPool
Definition: env_spec_w32.h:308
@ Success
Definition: eventcreate.c:712
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
#define WAIT_FOR_XXX_EMU_DELAY
Definition: tools.h:275
GLsizeiptr size
Definition: glext.h:5919
const GLubyte * c
Definition: glext.h:8905
GLenum const GLvoid * addr
Definition: glext.h:9621
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define InterlockedExchangeAdd
Definition: interlocked.h:181
#define a
Definition: ke_i.h:78
#define c
Definition: ke_i.h:80
#define PCHAR
Definition: match.c:90
#define ASSERT(a)
Definition: mode.c:44
#define KernelMode
Definition: asm.h:34
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
BOOLEAN NTAPI ExAcquireSharedWaitForExclusive(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:1222
long LONG
Definition: pedump.c:60
static ULONG Timeout
Definition: ping.c:61
VOID UDFDebugConvertExclusiveToSharedLite(IN PERESOURCE Resource, IN ERESOURCE_THREAD ResourceThreadId, ULONG BugCheckId, ULONG Line)
BOOLEAN UDFDebugAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait, ULONG BugCheckId, ULONG Line)
LONG UDFDebugInterlockedIncrement(IN PLONG addr, ULONG BugCheckId, ULONG Line)
NTSTATUS UDFDebugInitializeResourceLite(IN PERESOURCE Resource, IN ERESOURCE_THREAD ResourceThreadId, ULONG BugCheckId, ULONG Line)
LONG UDFDebugInterlockedDecrement(IN PLONG addr, ULONG BugCheckId, ULONG Line)
VOID UDFDebugDeleteResource(IN PERESOURCE Resource, IN ERESOURCE_THREAD ResourceThreadId, ULONG BugCheckId, ULONG Line)
LONG UDFDebugInterlockedExchangeAdd(IN PLONG addr, IN LONG i, ULONG BugCheckId, ULONG Line)
BOOLEAN UDFDebugAcquireResourceSharedLite(IN PERESOURCE Resource, IN BOOLEAN Wait, ULONG BugCheckId, ULONG Line)
BOOLEAN UDFDebugAcquireSharedWaitForExclusive(IN PERESOURCE Resource, IN BOOLEAN Wait, ULONG BugCheckId, ULONG Line)
VOID UDFDebugReleaseResourceForThreadLite(IN PERESOURCE Resource, IN ERESOURCE_THREAD ResourceThreadId, ULONG BugCheckId, ULONG Line)
BOOLEAN UDFDebugAcquireSharedStarveExclusive(IN PERESOURCE Resource, IN BOOLEAN Wait, ULONG BugCheckId, ULONG Line)
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
NTSTATUS DbgWaitForSingleObject_(IN PVOID Object, IN PLARGE_INTEGER Timeout OPTIONAL)
#define STATUS_SUCCESS
Definition: shellext.h:65
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
Definition: ncftp.h:79
uint32_t * PULONG
Definition: typedefs.h:59
INT POOL_TYPE
Definition: typedefs.h:78
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define IN
Definition: typedefs.h:39
int32_t * PLONG
Definition: typedefs.h:58
uint32_t ULONG
Definition: typedefs.h:59
char * PCHAR
Definition: typedefs.h:51
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define UDFPrint(Args)
Definition: udffs.h:225
LONGLONG QuadPart
Definition: typedefs.h:114
_Must_inspect_result_ _In_ WDFCOLLECTION _In_ WDFOBJECT Object
_In_ WDFDPC _In_ BOOLEAN Wait
Definition: wdfdpc.h:170
_In_ ERESOURCE_THREAD ResourceThreadId
Definition: exfuncs.h:1052
ULONG_PTR ERESOURCE_THREAD
Definition: extypes.h:208
@ Executive
Definition: ketypes.h:415