On TlsFree, clear the released TLS index in all threads.

diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index 3fc3b0d..c61ef40 100644
--- a/dlls/ntdll/nt.c
+++ b/dlls/ntdll/nt.c
@@ -164,25 +164,6 @@
 }
 
 /*
- *	Thread
- */
-
-/******************************************************************************
- *  NtSetInformationThread		[NTDLL.@]
- *  ZwSetInformationThread		[NTDLL.@]
- */
-NTSTATUS WINAPI NtSetInformationThread(
-	HANDLE ThreadHandle,
-	THREADINFOCLASS ThreadInformationClass,
-	PVOID ThreadInformation,
-	ULONG ThreadInformationLength)
-{
-	FIXME("(%p,0x%08x,%p,0x%08lx),stub!\n",
-	ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength);
-	return 0;
-}
-
-/*
  *	Token
  */
 
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 3be2fef..f28e2ed 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -217,7 +217,7 @@
 @ stdcall NtSetInformationKey(long long ptr long)
 @ stdcall NtSetInformationObject(long long ptr long)
 @ stdcall NtSetInformationProcess(long long long long)
-@ stdcall NtSetInformationThread(long long long long)
+@ stdcall NtSetInformationThread(long long ptr long)
 @ stub NtSetInformationToken
 @ stdcall NtSetIntervalProfile(long long)
 @ stub NtSetIoCompletion
@@ -746,7 +746,7 @@
 @ stdcall ZwSetInformationKey(long long ptr long) NtSetInformationKey
 @ stdcall ZwSetInformationObject(long long ptr long) NtSetInformationObject
 @ stdcall ZwSetInformationProcess(long long long long) NtSetInformationProcess
-@ stdcall ZwSetInformationThread(long long long long) NtSetInformationThread
+@ stdcall ZwSetInformationThread(long long ptr long) NtSetInformationThread
 @ stub ZwSetInformationToken
 @ stdcall ZwSetIntervalProfile(long long) NtSetIntervalProfile
 @ stub ZwSetIoCompletion
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index 67868a4..87ceaeb 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -107,7 +107,13 @@
     if (self)
     {
         if (last) exit( exit_code );
-        else SYSDEPS_ExitThread( exit_code );
+        else
+        {
+            RtlAcquirePebLock();
+            RemoveEntryList( &NtCurrentTeb()->TlsLinks );
+            RtlReleasePebLock();
+            SYSDEPS_ExitThread( exit_code );
+        }
     }
     return ret;
 }
@@ -235,3 +241,57 @@
         return STATUS_NOT_IMPLEMENTED;
     }
 }
+
+
+/******************************************************************************
+ *              NtSetInformationThread  (NTDLL.@)
+ *              ZwSetInformationThread  (NTDLL.@)
+ */
+NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
+                                        LPCVOID data, ULONG length )
+{
+    switch(class)
+    {
+    case ThreadZeroTlsCell:
+        if (handle == GetCurrentThread())
+        {
+            LIST_ENTRY *entry = &NtCurrentTeb()->TlsLinks;
+            DWORD index;
+
+            if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
+            index = *(DWORD *)data;
+            if (index >= 64) return STATUS_INVALID_PARAMETER;
+            RtlAcquirePebLock();
+            do
+            {
+                TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
+                teb->TlsSlots[index] = 0;
+                entry = entry->Flink;
+            } while (entry != &NtCurrentTeb()->TlsLinks);
+            RtlReleasePebLock();
+            return STATUS_SUCCESS;
+        }
+        FIXME( "ZeroTlsCell not supported on other threads\n" );
+        return STATUS_NOT_IMPLEMENTED;
+
+    case ThreadBasicInformation:
+    case ThreadTimes:
+    case ThreadPriority:
+    case ThreadBasePriority:
+    case ThreadAffinityMask:
+    case ThreadImpersonationToken:
+    case ThreadDescriptorTableEntry:
+    case ThreadEnableAlignmentFaultFixup:
+    case ThreadEventPair_Reusable:
+    case ThreadQuerySetWin32StartAddress:
+    case ThreadPerformanceCount:
+    case ThreadAmILastThread:
+    case ThreadIdealProcessor:
+    case ThreadPriorityBoost:
+    case ThreadSetTlsArrayAddress:
+    case ThreadIsIoPending:
+    default:
+        FIXME( "info class %d not supported yet\n", class );
+        return STATUS_NOT_IMPLEMENTED;
+    }
+}
diff --git a/include/thread.h b/include/thread.h
index f9d8379..dd7d0db 100644
--- a/include/thread.h
+++ b/include/thread.h
@@ -128,7 +128,8 @@
     USHORT       StaticUnicodeBuffer[261];   /* -2- c00 used by advapi32 */
     PVOID        DeallocationStack;          /* -2- e0c Base of the stack */
     LPVOID       TlsSlots[64];               /* -2- e10 Thread local storage */
-    DWORD        pad8[3];                    /* --n f10 */
+    LIST_ENTRY   TlsLinks;                   /* -2- f10 */
+    DWORD        pad8[1];                    /* --n f18 */
     PVOID        ReservedForNtRpc;           /* -2- f1c used by rpcrt4 */
     DWORD        pad9[24];                   /* --n f20 */
     PVOID        ReservedForOle;             /* -2- f80 used by ole32 (IErrorInfo*) */
diff --git a/include/winternl.h b/include/winternl.h
index f471b85..1ef12d8 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -171,7 +171,7 @@
     WCHAR           StaticUnicodeBuffer[261];   /* c00 used by advapi32 */
     PVOID           DeallocationStack;          /* e0c */
     PVOID           TlsSlots[64];               /* e10 */
-    BYTE            Reserved3[8];               /* f10 */
+    LIST_ENTRY      TlsLinks;                   /* f10 */
     PVOID           Reserved4[26];              /* f18 */
     PVOID           ReservedForOle;             /* f80 Windows 2000 only */
     PVOID           Reserved5[4];               /* f84 */
@@ -1019,6 +1019,7 @@
 NTSTATUS  WINAPI NtSetInformationFile(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS);
 NTSTATUS  WINAPI NtSetInformationKey(HKEY,const int,PVOID,ULONG);
 NTSTATUS  WINAPI NtSetInformationObject(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG);
+NTSTATUS  WINAPI NtSetInformationThread(HANDLE,THREADINFOCLASS,LPCVOID,ULONG);
 NTSTATUS  WINAPI NtSetSecurityObject(HANDLE,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR);
 NTSTATUS  WINAPI NtSetSystemTime(const LARGE_INTEGER*,LARGE_INTEGER*);
 NTSTATUS  WINAPI NtSetTimer(HANDLE, const LARGE_INTEGER*, PTIMERAPCROUTINE, PVOID, BOOLEAN, ULONG, BOOLEAN*);
diff --git a/scheduler/process.c b/scheduler/process.c
index bec3d71..266e285 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -1502,8 +1502,7 @@
         return FALSE;
     }
     *bits &= ~mask;
-    NtCurrentTeb()->TlsSlots[index] = 0;
-    /* FIXME: should zero all other thread values */
+    NtSetInformationThread( GetCurrentThread(), ThreadZeroTlsCell, &index, sizeof(index) );
     RtlReleasePebLock();
     return TRUE;
 }
diff --git a/scheduler/thread.c b/scheduler/thread.c
index 0738f64..436f024 100644
--- a/scheduler/thread.c
+++ b/scheduler/thread.c
@@ -70,6 +70,7 @@
     teb->wait_fd[1] = -1;
     teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
     teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer;
+    InitializeListHead(&teb->TlsLinks);
     teb->teb_sel = wine_ldt_alloc_fs();
     return (teb->teb_sel != 0);
 }
@@ -268,12 +269,18 @@
     teb->entry_point = start;
     teb->entry_arg   = param;
     teb->htask16     = GetCurrentTask();
+    RtlAcquirePebLock();
+    InsertHeadList( &NtCurrentTeb()->TlsLinks, &teb->TlsLinks );
+    RtlReleasePebLock();
 
     if (id) *id = tid;
     if (SYSDEPS_SpawnThread( THREAD_Start, teb ) == -1)
     {
         CloseHandle( handle );
         close( request_pipe[1] );
+        RtlAcquirePebLock();
+        RemoveEntryList( &teb->TlsLinks );
+        RtlReleasePebLock();
         THREAD_FreeTEB( teb );
         return 0;
     }
@@ -307,6 +314,9 @@
     else
     {
         LdrShutdownThread();
+        RtlAcquirePebLock();
+        RemoveEntryList( &NtCurrentTeb()->TlsLinks );
+        RtlReleasePebLock();
         SYSDEPS_ExitThread( code );
     }
 }