Пример #1
0
task_api void uninit_lib()
{
    if( InterlockedExchangeAdd(&ref_count, -1) == 1 ){
        DeleteCriticalSection(&(task_list_lock));
    }
}
Пример #2
0
static void*
alloc_from_fragment (Fragment *frag, size_t size)
{
	char *p = frag->fragment_next;
	char *end = p + size;

	if (end > frag->fragment_end)
		return NULL;

	/* p = frag->fragment_next must happen before */
	mono_memory_barrier ();

	if (InterlockedCompareExchangePointer ((volatile gpointer*)&frag->fragment_next, end, p) != p)
		return NULL;

	if (frag->fragment_end - end < SGEN_MAX_NURSERY_WASTE) {
		Fragment *next, **prev_ptr;
		
		/*
		 * Before we clean the remaining nursery, we must claim the remaining space
		 * as it could end up been used by the range allocator since it can end up
		 * allocating from this dying fragment as it doesn't respect SGEN_MAX_NURSERY_WASTE
		 * when doing second chance allocation.
		 */
		if (mono_sgen_get_nursery_clear_policy () == CLEAR_AT_TLAB_CREATION && claim_remaining_size (frag, end)) {
			/* Clear the remaining space, pinning depends on this. FIXME move this to use phony arrays */
			memset (end, 0, frag->fragment_end - end);
			HEAVY_STAT (InterlockedExchangeAdd (&stat_wasted_bytes_trailer, frag->fragment_end - end));
#ifdef NALLOC_DEBUG
			add_alloc_record (end, frag->fragment_end - end, BLOCK_ZEROING);
#endif
		}

		prev_ptr = find_previous_pointer_fragment (frag);

		/*Use Michaels linked list remove*/

		/*prev_ptr will be null is the fragment was removed concurrently */
		while (prev_ptr) {
			next = frag->next;

			/*already deleted*/
			if (!get_mark (next)) {
				/*frag->next read must happen before the first CAS*/
				mono_memory_write_barrier ();

				/*Fail if the next done is removed concurrently and its CAS wins */
				if (InterlockedCompareExchangePointer ((volatile gpointer*)&frag->next, mask (next, 1), next) != next) {
					continue;
				}
			}

			/* The second CAS must happen after the first CAS or frag->next. */
			mono_memory_write_barrier ();

			/* Fail if the previous node was deleted and its CAS wins */
			if (InterlockedCompareExchangePointer ((volatile gpointer*)prev_ptr, next, frag) != frag) {
				prev_ptr = find_previous_pointer_fragment (frag);
				continue;
			}

			/* No need to membar here since the worst that can happen is a CAS failure. */
			do {
				frag->next_free = fragment_freelist;
			} while (InterlockedCompareExchangePointer ((volatile gpointer*)&fragment_freelist, frag, frag->next_free) != frag->next_free);

			break;
		}
	}

	return p;
}
Пример #3
0
/*** Nursery memory allocation ***/
void
mono_sgen_nursery_retire_region (void *address, ptrdiff_t size)
{
	HEAVY_STAT (InterlockedExchangeAdd (&stat_wasted_bytes_discarded_fragments, size));
}
Пример #4
0
static NTSTATUS
V4vCtrlBind(XENV4V_EXTENSION *pde, XENV4V_CONTEXT *ctx, V4V_BIND_VALUES *bvs)
{
    NTSTATUS            status = STATUS_SUCCESS;
    LONG                val;
    KLOCK_QUEUE_HANDLE  lqh;
    XENV4V_RING        *robj;
    uint32_t            port;

    // Use a simple guard variable to enforce the state transition order
    val = InterlockedExchangeAdd(&ctx->state, 0);
    if (val != XENV4V_STATE_IDLE) {
        TraceWarning(("state not IDLE, cannot complete bind request\n"));
        return STATUS_INVALID_DEVICE_REQUEST;
    }

    ASSERT(ctx->ringObject == NULL);

    do {
        if ((bvs->ringId.addr.domain != V4V_DOMID_NONE)&&
            (bvs->ringId.addr.domain != DOMID_INVALID_COMPAT)) {
            TraceWarning(("failure - ring ID domain must be V4V_DOMID_NONE - value: 0x%x\n",
                         bvs->ringId.addr.domain));
            status = STATUS_INVALID_PARAMETER;
            break;
        }

        robj = V4vAllocateRing(ctx->ringLength);
        if (robj == NULL) {    
            TraceError(("failed to allocate the ring\n"));
            status = STATUS_NO_MEMORY;
            break;
        }
        robj->ring->id = bvs->ringId;

        // Have to grab this outside of lock at IRQL PASSIVE    
        port = V4vRandomPort(pde);

        // Lock this section since we access the list
        KeAcquireInStackQueuedSpinLock(&pde->ringLock, &lqh);

        if (robj->ring->id.addr.port == V4V_PORT_NONE) {
            robj->ring->id.addr.port = V4vSparePortNumber(pde, port);
        }
        else if (V4vRingIdInUse(pde, &robj->ring->id)) {
            KeReleaseInStackQueuedSpinLock(&lqh);
            TraceWarning(("ring ID already in use, cannot bind\n"));
            status = STATUS_INVALID_DEVICE_REQUEST;
            break;
        }
        
        // Now register the ring.
        status = V4vRegisterRing(robj);
        if (!NT_SUCCESS(status)) {
            KeReleaseInStackQueuedSpinLock(&lqh);
            TraceError(("failed in register ring hypercall - error: 0x%x\n", status));
            break;
        }
        robj->registered = TRUE;

        // Link it to the main list and set our pointer to it
        V4vLinkToRingList(pde, robj);
        ctx->ringObject = robj;

        KeReleaseInStackQueuedSpinLock(&lqh);

        InterlockedExchange(&ctx->type, XENV4V_TYPE_DATAGRAM);
        InterlockedExchange(&ctx->state, XENV4V_STATE_BOUND);        
    } while (FALSE);

    if (!NT_SUCCESS(status)) {
        // If it failed, undo everything - this will remove it from the list
        if (ctx->ringObject != NULL) {
            V4vReleaseRing(pde, ctx->ringObject);
        }
    }

    return status;
}
Пример #5
0
NTSTATUS NTAPI
V4vDispatchDeviceControl(PDEVICE_OBJECT fdo, PIRP irp)
{
    NTSTATUS            status = STATUS_SUCCESS;
    PIO_STACK_LOCATION  isl;
    ULONG               ioControlCode;
    PVOID               ioBuffer;
    ULONG               ioInLen;
    ULONG               ioOutLen;
    XENV4V_EXTENSION   *pde = V4vGetDeviceExtension(fdo);
    XENV4V_CONTEXT     *ctx;
    LONG                ds;

    TraceVerbose(("====> '%s'.\n", __FUNCTION__));

    isl           = IoGetCurrentIrpStackLocation(irp);
    ioControlCode = isl->Parameters.DeviceIoControl.IoControlCode;
    ioBuffer      = irp->AssociatedIrp.SystemBuffer;
    ioInLen       = isl->Parameters.DeviceIoControl.InputBufferLength;
    ioOutLen      = isl->Parameters.DeviceIoControl.OutputBufferLength;
    ctx           = (XENV4V_CONTEXT*)isl->FileObject->FsContext;

    TraceVerbose((" =IOCTL= 0x%x\n", ioControlCode));

    irp->IoStatus.Information = 0;

    ds = InterlockedExchangeAdd(&pde->state, 0);
    if (ds & XENV4V_DEV_STOPPED) {
        TraceVerbose(("aborting IOCTL IRP, device is in the stopped state.\n"));
        irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
        IoCompleteRequest(irp, IO_NO_INCREMENT);
        TraceVerbose(("<==== '%s'.\n", __FUNCTION__));
        return STATUS_INVALID_DEVICE_STATE;
    }

    switch (ioControlCode) {
#if defined(_WIN64)
    case V4V_IOCTL_INITIALIZE_32:
    {
        V4V_INIT_VALUES_32 *invs32 = (V4V_INIT_VALUES_32*)ioBuffer;
        if (ioInLen == sizeof(V4V_INIT_VALUES_32)) {
            V4V_INIT_VALUES init;
            init.rxEvent = invs32->rxEvent;
            init.ringLength = invs32->ringLength;
            status = V4vCtrlInitializeFile(ctx, &init, irp);
        }
        else {
            TraceError(("invalid initialization values.\n"));
            status = STATUS_INVALID_PARAMETER;
        }

        break;
    }
#endif
    case V4V_IOCTL_INITIALIZE:
    {
        V4V_INIT_VALUES *invs = (V4V_INIT_VALUES*)ioBuffer;
        if (ioInLen == sizeof(V4V_INIT_VALUES)) {
            status = V4vCtrlInitializeFile(ctx, invs, irp);
        }
        else {
            TraceError(("invalid initialization values.\n"));
            status = STATUS_INVALID_PARAMETER;
        }

        break;
    }
    case V4V_IOCTL_BIND:
    {
        V4V_BIND_VALUES *bvs = (V4V_BIND_VALUES*)ioBuffer;
        if (ioInLen == sizeof(V4V_BIND_VALUES)) {
            status = V4vCtrlBind(pde, ctx, bvs);
        }
        else {
            TraceError(("invalid bind values.\n"));
            status = STATUS_INVALID_PARAMETER;
        }

        break;
    }
    case V4V_IOCTL_LISTEN:
    {
        V4V_LISTEN_VALUES *lvs = (V4V_LISTEN_VALUES*)ioBuffer;
        if (ioInLen == sizeof(V4V_LISTEN_VALUES)) {
            status = V4vCtrlListen(ctx, lvs);
        }
        else {
            TraceError(("invalid listen values.\n"));
            status = STATUS_INVALID_PARAMETER;
        }

        break;
    }
#if defined(_WIN64)
    case V4V_IOCTL_ACCEPT_32: // Fall through
#endif
    case V4V_IOCTL_ACCEPT:
    {
        status = V4vCtrlAccept(pde, ctx, ioControlCode, ioBuffer, ioInLen, irp);
        break;
    }
    case V4V_IOCTL_CONNECT:
    {
        V4V_CONNECT_VALUES *cvs = (V4V_CONNECT_VALUES*)ioBuffer;
        if (ioInLen == sizeof(V4V_CONNECT_VALUES)) {
            status = V4vCtrlConnect(pde, ctx, cvs, irp);
        }
        else {
            TraceError(("invalid connect values.\n"));
            status = STATUS_INVALID_PARAMETER;
        }
      
        break;
    }
    case V4V_IOCTL_WAIT:
    {
        V4V_WAIT_VALUES *wvs = (V4V_WAIT_VALUES*)ioBuffer;
        if (ioInLen == sizeof(V4V_WAIT_VALUES)) {
            status = V4vCtrlConnectWait(pde, ctx, wvs, irp);
        }
        else {
            TraceError(("invalid connect wait values.\n"));
            status = STATUS_INVALID_PARAMETER;
        }

        break;
    }
    case V4V_IOCTL_DISCONNECT:
    {
        status = V4vCtrlDisconnect(pde, ctx);      
        break;
    }
    case V4V_IOCTL_GETINFO:
    {
        V4V_GETINFO_VALUES *gi = (V4V_GETINFO_VALUES*)ioBuffer;
        if (ioInLen == sizeof(V4V_GETINFO_VALUES)) {
            status = V4vCtrlGetInfo(ctx, gi);
        }
        else {
            TraceError(("invalid get info values.\n"));
	        status = STATUS_INVALID_PARAMETER;
        }

        if (NT_SUCCESS(status)) {
            irp->IoStatus.Information = sizeof(V4V_GETINFO_VALUES);
        }

        break;
    }
    case V4V_IOCTL_DUMPRING:
    {
        status = V4vCtrlDumpRing(ctx);
        break;
    }
    default:
        status = STATUS_INVALID_PARAMETER;		
    }

    if (status != STATUS_PENDING) {
        irp->IoStatus.Status = status;
        IoCompleteRequest(irp, IO_NO_INCREMENT);
    }

    TraceVerbose(("<==== '%s'.\n", __FUNCTION__));

    return status;
}
Пример #6
0
int
SemOp(int semid, struct sembuf *semopbuf, DWORD procid, int piid, IPCT *ipct)
{
	int	i;
	BOOL	ret;
	DWORD	dwret;
	HANDLE	hsem;
#ifndef	TERMINAL_SERVICE
	char	semstr[16];
#else
	char	semstr[30];
#endif	/* TERMINAL_SERVICE */

#ifndef	TERMINAL_SERVICE
	MakeSemstr(semstr, semopbuf->sem_num, semid, ipct->semt[semid].key);
#else
	OSVERSIONINFOEX osvi;

	ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

	if( !GetVersionEx ((OSVERSIONINFO *) &osvi) )
	{
	  // If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO.
		osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
		GetVersionEx( (OSVERSIONINFO *) &osvi );
	}

	if( osvi.dwMajorVersion >= 5 )	/* Windows 2000 */
		MakeGlobalSemstr(semstr, semopbuf->sem_num, semid, ipct->semt[semid].key);
	else
		MakeSemstr(semstr, semopbuf->sem_num, semid, ipct->semt[semid].key);
#endif	/* TERMINAL_SERVICE */
	hsem=OpenSemaphore(SEMAPHORE_ALL_ACCESS, TRUE, semstr);
	if (hsem==NULL)
	{
		errno=GetLastError();

		return -1;
	}

	if (semopbuf->sem_op<0)
	{
		if (ipct->semb[semid][semopbuf->sem_num].semval
			>= abs((int)semopbuf->sem_op))
			ipct->semb[semid][semopbuf->sem_num].semncnt++;

		if (ipct->semb[semid][semopbuf->sem_num].semval
			< abs((int)semopbuf->sem_op))
		{
			if (semopbuf->sem_flg & IPC_NOWAIT)
			{
				ipct->semb[semid][semopbuf->sem_num].sempid=procid;
				CloseHandle(hsem);
				return 0;
			}
		}

		for (i=0; i<abs((int)semopbuf->sem_op); i++)
		{
/**************
			do
			{
				dwret=MsgWaitForMultipleObjects(1, &hsem, 
					FALSE, INFINITE, 
					QS_SENDMESSAGE|QS_POSTMESSAGE|QS_TIMER);
***************/
			dwret=WaitForSingleObject(hsem, INFINITE);
			switch (dwret)
			{
/*****************
			case	WAIT_OBJECT_0 + 1 :
				if (l_peekmessage()<0)
				{
					CloseHandle(hsem);
					return -1;
				}
				break;
*****************/

			case	WAIT_OBJECT_0	:
/* by KJC 98.09.24 **************************************
				ipct->semb[semid][semopbuf->sem_num].semval--;
***********************************************************/
				InterlockedDecrement(&ipct->semb[semid][semopbuf->sem_num].semval);
/***********************************************************/
				break;
			case	WAIT_TIMEOUT	:
			case	WAIT_FAILED	:
				errno=GetLastError();
			default	:
				CloseHandle(hsem);
				return -1;
			}
/***************
			} while (dwret==(WAIT_OBJECT_0 + 1));
***************/

			if (semopbuf->sem_flg & SEM_UNDO)
			{
				ipct->pseminfo[piid].semadj[semid][semopbuf->sem_num]++;
			}
		}

		ipct->semb[semid][semopbuf->sem_num].sempid=procid;
		ipct->semb[semid][semopbuf->sem_num].semncnt--;
	//	CloseHandle(hsem);
	}
	else if (semopbuf->sem_op>0)
	{
		ret=ReleaseSemaphore(hsem, semopbuf->sem_op, NULL);
		if (ret==FALSE)
		{

			CloseHandle(hsem);
			return -1;
		}
		ipct->semb[semid][semopbuf->sem_num].sempid=procid;
/* by KJC 98.9.24 ********************************
		ipct->semb[semid][semopbuf->sem_num].semval+=(int)semopbuf->sem_op;
***********************************************************/
		InterlockedExchangeAdd(&ipct->semb[semid][semopbuf->sem_num].semval, (long)semopbuf->sem_op);
/***********************************************************/
	//	CloseHandle(hsem);

		if (semopbuf->sem_flg & SEM_UNDO)
		{
			ipct->pseminfo[piid].semadj[semid][semopbuf->sem_num]-=(int)semopbuf->sem_op;
		}

	}
	else
	{
		if (!ipct->semb[semid][semopbuf->sem_num].semval)
		{
			CloseHandle(hsem);
			return 0;
		}

		if (semopbuf->sem_flg & IPC_NOWAIT)
		{
			CloseHandle(hsem);
			return 0;
		}

		ipct->semb[semid][semopbuf->sem_num].sempid=procid;
		ipct->semb[semid][semopbuf->sem_num].semzcnt++;
		/*###################################*/
		/*###################################*/

	}
	
	CloseHandle(hsem);
	return 0;
}
Пример #7
0
static NTSTATUS
V4vCtrlAccept(XENV4V_EXTENSION *pde, XENV4V_CONTEXT *ctx, ULONG ioc, VOID *iob, ULONG iol, PIRP irp)
{
    NTSTATUS            status = STATUS_SUCCESS;
    LONG                val;
    V4V_INIT_VALUES     init;
    FILE_OBJECT        *pfo = NULL;
    XENV4V_CONTEXT     *actx;
    XENV4V_INSERT       ins = {FALSE};
    HANDLE              fh;
    HANDLE              rxe;
    V4V_ACCEPT_PRIVATE *priv;

    val = InterlockedExchangeAdd(&ctx->state, 0);
    if (val != XENV4V_STATE_LISTENING) {
        TraceWarning(("state not LISTENING, cannot complete accept request\n"));
        return STATUS_INVALID_DEVICE_REQUEST;
    }    

    // Handle 32b/64b thunk sructures here and test input
#if defined(_WIN64)
    if (ioc == V4V_IOCTL_ACCEPT_32)
    {
        V4V_ACCEPT_VALUES_32 *avs32 = (V4V_ACCEPT_VALUES_32*)iob;

        if (iol != sizeof(V4V_ACCEPT_VALUES_32)) {
            TraceError(("invalid accept values.\n"));
            return STATUS_INVALID_PARAMETER;
        }        
        fh  = avs32->fileHandle;
        rxe = avs32->rxEvent;
        priv = (V4V_ACCEPT_PRIVATE*)((UCHAR*)avs32 + FIELD_OFFSET(V4V_ACCEPT_VALUES_32, priv));
    }
    else
#endif
    {
        V4V_ACCEPT_VALUES *avs = (V4V_ACCEPT_VALUES*)iob;

        UNREFERENCED_PARAMETER(ioc);

        if (iol != sizeof(V4V_ACCEPT_VALUES)) {
            TraceError(("invalid accept values.\n"));
            return STATUS_INVALID_PARAMETER;
        }        
        fh  = avs->fileHandle;
        rxe = avs->rxEvent;
        priv = (V4V_ACCEPT_PRIVATE*)((UCHAR*)avs + FIELD_OFFSET(V4V_ACCEPT_VALUES, priv));
    }

    // Any IRPs that are queued are given a sanity initialization
    V4vInitializeIrp(irp);

    // Get a reference to the file object for the handle
    status = ObReferenceObjectByHandle(fh,
                                       0,
                                       *IoFileObjectType,
                                       irp->RequestorMode,
                                       &pfo,
                                       NULL);
    if (!NT_SUCCESS(status)) {
        TraceError(("failed to get a reference to the accepter file object - error: 0x%x\n", status));
        return status;
    }
    actx = (XENV4V_CONTEXT*)pfo->FsContext;
    ObDereferenceObject(pfo);

    // Store the referenced acceptor context in the IOCTL buffer so we can access it at > PASSIVE later.
    V4vAddRefContext(pde, actx);
#if defined(_WIN64)
    priv->q.a = (ULONG64)actx;
#else
    priv->d.a = (ULONG32)actx;
#endif

    // Do the base initialization of the file object context
    init.rxEvent = rxe;
    init.ringLength = ctx->ringLength; // shared ring length
    status = V4vCtrlInitializeFile(actx, &init, irp);
    if (!NT_SUCCESS(status)) {
        V4vReleaseContext(pde, actx);
        TraceError(("failed to initialize the accepter file object - error: 0x%x\n", status));
        return status;
    }

    // Now initialize the accepter specific state and associate the accepter
    // with the listener context and ring.
    KeInitializeSpinLock(&actx->u.accepter.dataLock);
    actx->u.accepter.dataList = NULL;
    actx->u.accepter.dataTail = NULL;
    V4vAddRefContext(pde, ctx);
    V4vAddRefRing(pde, ctx->ringObject);
    actx->u.accepter.listenerContext = ctx;
    actx->ringObject = ctx->ringObject;

    // Now it becomes an accepter type for ever more
    InterlockedExchange(&actx->type, XENV4V_TYPE_ACCEPTER);

    // After this transition, we will wait for a SYN (may be one in the queue already).
    InterlockedExchange(&actx->state, XENV4V_STATE_ACCEPTING);

    // Flag it
    irp->Tail.Overlay.DriverContext[0] = 
        (PVOID)(ULONG_PTR)(XENV4V_PEEK_STREAM|XENV4V_PEEK_ACCEPT|XENV4V_PEEK_IOCTL);

    // Always queue it to the back and marks it pending. If it fails to be queued then
    // the user mode call will close the new handle.
    status = IoCsqInsertIrpEx(&pde->csqObject, irp, NULL, &ins);
    if (NT_SUCCESS(status)) {
        status = STATUS_PENDING;
        // Drive any accepts
        V4vDoAccepts(pde, ctx);
    }

    return status;
}
Пример #8
0
INLINE INT32 interlocked_add(INT32 volatile *ptr, INT32 add)
{
	return InterlockedExchangeAdd((LPLONG)ptr, add) + add;
}
Пример #9
0
atomic_t atomicExchangeAdd(volatile atomic_t& value, atomic_t n)
{
    return InterlockedExchangeAdd(const_cast<atomic_t*>(&value), n);
}
Пример #10
0
int32_t atom_add(int32_t *dest, int32_t incr)
{
    return InterlockedExchangeAdd((LONG *)dest, incr) + incr;
}
Пример #11
0
long juce_InterlockedExchangeAdd (volatile long* a, long b) noexcept             { return InterlockedExchangeAdd (a, b); }
Пример #12
0
int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
{
    *ret = InterlockedExchangeAdd(val, amount) + amount;
    return 1;
}
static WorkItemState GetWorkItemState (EncryptionThreadPoolWorkItem *workItem)
{
	return InterlockedExchangeAdd ((LONG *) &workItem->State, 0);
}
Пример #14
-1
// Write procedure of the device
NTSTATUS SlDeviceWriteProc(DEVICE_OBJECT *device_object, IRP *irp)
{
	SL_DEVICE *dev = *((SL_DEVICE **)device_object->DeviceExtension);
	NTSTATUS ret = STATUS_UNSUCCESSFUL;
	IO_STACK_LOCATION *irp_stack = IoGetCurrentIrpStackLocation(irp);
	UINT ret_size = 0;

	if (dev->IsBasicDevice == false)
	{
		// Adapter device
		SL_FILE *f = irp_stack->FileObject->FsContext;

		if (irp_stack->Parameters.Write.Length == SL_EXCHANGE_BUFFER_SIZE)
		{
			UCHAR *buf = irp->UserBuffer;

			if (dev->Halting || dev->Adapter->Halt || buf == NULL)
			{
				// Halting
			}
			else
			{
				// Write the packet
				MDL *mdl;
				UINT num = SL_NUM_PACKET(buf);

				mdl = IoAllocateMdl(buf, SL_EXCHANGE_BUFFER_SIZE, false, false, NULL);
				if (mdl != NULL)
				{
					MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);
				}

				ret = true;
				ret_size = SL_EXCHANGE_BUFFER_SIZE;

				if (num >= 1 && num <= SL_MAX_PACKET_EXCHANGE)
				{
					UINT i, j;
					NET_BUFFER_LIST *nbl_head = NULL;
					NET_BUFFER_LIST *nbl_tail = NULL;
					UINT num_packets = 0;
					NDIS_HANDLE adapter_handle = NULL;

					SlLock(f->Adapter->Lock);

					if (f->Adapter->NumPendingSendPackets <= SL_MAX_PACKET_QUEUED)
					{
						// Admit to send only if the number of packets being transmitted does not exceed the specified limit
						adapter_handle = f->Adapter->AdapterHandle;
					}

					if (adapter_handle != NULL)
					{
						// Lock the file list which opens the same adapter
						SlLockList(dev->FileList);
						for (j = 0;j < SL_LIST_NUM(dev->FileList);j++)
						{
							SL_FILE *other = SL_LIST_DATA(dev->FileList, j);

							if (other != f)
							{
								// Lock the receive queue of other file lists
								SlLock(other->RecvLock);

								other->SetEventFlag = false;
							}
						}

						for (i = 0;i < num;i++)
						{
							UINT packet_size = SL_SIZE_OF_PACKET(buf, i);
							UCHAR *packet_buf;
							NET_BUFFER_LIST *nbl = NULL;
							bool ok = false;

							if (packet_size > SL_MAX_PACKET_SIZE)
							{
								packet_size = SL_MAX_PACKET_SIZE;
							}
							else if (packet_size < SL_PACKET_HEADER_SIZE)
							{
								packet_size = SL_PACKET_HEADER_SIZE;
							}

							packet_buf = (UCHAR *)SL_ADDR_OF_PACKET(buf, i);

							for (j = 0;j < SL_LIST_NUM(dev->FileList);j++)
							{
								SL_FILE *other = SL_LIST_DATA(dev->FileList, j);

								if (other != f)
								{
									// Insert into the receive queue of the other file lists
									if (other->NumRecvPackets < SL_MAX_PACKET_QUEUED)
									{
										SL_PACKET *q = SlMalloc(sizeof(SL_PACKET));

										SlCopy(q->Data, packet_buf, packet_size);
										q->Size = packet_size;
										q->Next = NULL;

										if (other->RecvPacketHead == NULL)
										{
											other->RecvPacketHead = q;
										}
										else
										{
											other->RecvPacketTail->Next = q;
										}

										other->RecvPacketTail = q;

										other->NumRecvPackets++;

										other->SetEventFlag = true;
									}
								}
							}

							// Allocate a new NET_BUFFER_LIST
							if (f->NetBufferListPool != NULL)
							{
								nbl = NdisAllocateNetBufferList(f->NetBufferListPool, 16, 0);

								if (nbl != NULL)
								{
									nbl->SourceHandle = adapter_handle;
								}
							}

							if (nbl != NULL)
							{
								// Get the NET_BUFFER from the NET_BUFFER_LIST
								NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl);

								NET_BUFFER_LIST_NEXT_NBL(nbl) = NULL;

								if (nb != NULL && OK(NdisRetreatNetBufferDataStart(nb, packet_size, 0, NULL)))
								{
									// Buffer copy
									UCHAR *dst = NdisGetDataBuffer(nb, packet_size, NULL, 1, 0);

									if (dst != NULL)
									{
										SlCopy(dst, packet_buf, packet_size);

										ok = true;
									}
									else
									{
										NdisAdvanceNetBufferDataStart(nb, packet_size, false, NULL);
									}
								}
							}

							if (ok == false)
							{
								if (nbl != NULL)
								{
									NdisFreeNetBufferList(nbl);
								}
							}
							else
							{
								if (nbl_head == NULL)
								{
									nbl_head = nbl;
								}

								if (nbl_tail != NULL)
								{
									NET_BUFFER_LIST_NEXT_NBL(nbl_tail) = nbl;
								}

								nbl_tail = nbl;

								*((void **)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl)) = f;

								num_packets++;
							}
						}

						for (j = 0;j < SL_LIST_NUM(dev->FileList);j++)
						{
							SL_FILE *other = SL_LIST_DATA(dev->FileList, j);

							if (other != f)
							{
								// Release the receive queue of other file lists
								SlUnlock(other->RecvLock);

								// Set an event
								if (other->SetEventFlag)
								{
									SlSet(other->Event);
								}
							}
						}
						SlUnlockList(dev->FileList);

						if (nbl_head != NULL)
						{
							InterlockedExchangeAdd(&f->NumSendingPacketets, num_packets);
							InterlockedExchangeAdd(&f->Adapter->NumPendingSendPackets, num_packets);

							SlUnlock(f->Adapter->Lock);

							NdisSendNetBufferLists(adapter_handle, nbl_head, 0, 0);
						}
						else
						{
							SlUnlock(f->Adapter->Lock);
						}
					}
					else
					{
						SlUnlock(f->Adapter->Lock);
					}
				}

				if (mdl != NULL)
				{
					MmUnlockPages(mdl);
					IoFreeMdl(mdl);
				}
			}
		}
	}

	irp->IoStatus.Information = ret_size;
	irp->IoStatus.Status = ret;
	IoCompleteRequest(irp, IO_NO_INCREMENT);

	return ret;
}