Skip to content

Commit

Permalink
added CCLASH_Z7_OBJ=yes option.
Browse files Browse the repository at this point in the history
  • Loading branch information
inorton committed May 26, 2014
1 parent 2c4274e commit acfad81
Show file tree
Hide file tree
Showing 15 changed files with 332 additions and 147 deletions.
2 changes: 2 additions & 0 deletions CClash/CClash.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Management" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
Expand Down Expand Up @@ -68,6 +69,7 @@
<Compile Include="ICompilerCache.cs" />
<Compile Include="Logging.cs" />
<Compile Include="NullCompilerCache.cs" />
<Compile Include="ProcessUtils.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Settings.cs" />
Expand Down
2 changes: 1 addition & 1 deletion CClash/CClash.csproj.user
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<StartArguments>--cclash-server</StartArguments>
<StartArguments>--cclash-server --debug --pdb-to-z7</StartArguments>
</PropertyGroup>
</Project>
1 change: 1 addition & 0 deletions CClash/CClashMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class CClashRequest : CClashMessage
public IList<string> argv;
public string compiler;
public int tag;
public int pid;
}

[Serializable]
Expand Down
241 changes: 158 additions & 83 deletions CClash/CClashServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,15 @@ public sealed class CClashServer : IDisposable
bool quitnow = false;
DirectCompilerCacheServer cache;

int connections = 0;
/// <summary>
/// The maximum number of pending requests.
/// </summary>
public const int MaxServerThreads = 20;

public const int QuitAfterIdleMinutes = 10;

List<NamedPipeServerStream> serverPipes = new List<NamedPipeServerStream>();
List<Thread> serverThreads = new List<Thread>();

string mydocs = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

Expand All @@ -23,108 +31,175 @@ public CClashServer()
Directory.SetCurrentDirectory(mydocs);
}

DateTime lastYield = DateTime.Now;
void YieldLocks()
int busyThreads = 0;

public int BusyThreadCount
{
if (DateTime.Now.Subtract(lastYield).TotalSeconds > 5)
get
{
cache.YieldLocks();
lastYield = DateTime.Now;
return busyThreads;
}
}

public void Listen(string cachedir)
void ThreadIsBusy()
{

var mtx = new Mutex(false, "cclash_serv_" + cachedir.ToLower().GetHashCode());
lock (serverThreads)
{
busyThreads++;
}
}

try {
if (!mtx.WaitOne(500)) {
return; // some other process is holding it
}
} catch (AbandonedMutexException) {
// past server must have died!
void ThreadIsIdle()
{
lock (serverThreads)
{
busyThreads--;
}
}

DateTime lastRequest = DateTime.Now;

void ThreadBeforeProcessRequest()
{
lastRequest = DateTime.Now;
if (BusyThreadCount > Environment.ProcessorCount)
{
System.Threading.Thread.Sleep(60/Environment.ProcessorCount);
}
}

try {
Logging.Emit("server listening..");

using (var nss = new NamedPipeServerStream(MakePipeName(cachedir), PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.WriteThrough | PipeOptions.Asynchronous)) {
cache = new DirectCompilerCacheServer(cachedir);
var msgbuf = new List<byte>();
var rxbuf = new byte[256 * 1024];
DateTime lastConnection = DateTime.Now;

do {
// don't hog folders
System.IO.Directory.SetCurrentDirectory(mydocs);
Logging.Emit("server waiting..");
YieldLocks();
try {
connections++;

if (!nss.IsConnected) {
var w = nss.BeginWaitForConnection(null, null);
while (!w.AsyncWaitHandle.WaitOne(5000)) {
try {
YieldLocks();
} catch { }
if (quitnow) {
return;
}
if (DateTime.Now.Subtract(lastConnection).TotalSeconds > 90)
Stop();
}
nss.EndWaitForConnection(w);
lastConnection = DateTime.Now;
public void ConnectionThreadFn(object con)
{
using (var nss = con as NamedPipeServerStream)
{
try
{

while (!quitnow)
{
var w = nss.BeginWaitForConnection(null, null);
Logging.Emit("waiting for client..");
while (!w.AsyncWaitHandle.WaitOne(1000))
{
if (quitnow)
{
return;
}
}
nss.EndWaitForConnection(w);
Logging.Emit("got client");
if (nss.IsConnected)
{
Logging.Emit("server connected");
ThreadBeforeProcessRequest();
ThreadIsBusy();
ServiceRequest(nss);
ThreadIsIdle();
}
}
}
catch (IOException ex)
{
Logging.Error("server thread got {0}, {1}", ex.GetType().Name, ex.Message);
Logging.Error(":{0}", ex.ToString());
}
}
}

Logging.Emit("server connected..");
public void ServiceRequest(NamedPipeServerStream nss)
{
var msgbuf = new List<byte>(8192);
var rxbuf = new byte[256 * 1024];
int count = 0;
do
{
count = nss.Read(rxbuf, msgbuf.Count, rxbuf.Length);
if (count > 0)
{
msgbuf.AddRange(rxbuf.Take(count));
}

msgbuf.Clear();
int count = 0;
do {
count = nss.Read(rxbuf, msgbuf.Count, rxbuf.Length);
if (count > 0) {
msgbuf.AddRange(rxbuf.Take(count));
}
} while (!nss.IsMessageComplete);

} while (!nss.IsMessageComplete);
Logging.Emit("server read {0} bytes", msgbuf.Count);

Logging.Emit("server read {0} bytes", msgbuf.Count);
// deserialize message from msgbuf
var req = CClashMessage.Deserialize<CClashRequest>(msgbuf.ToArray());
cache.Setup(); // needed?
Logging.Emit("processing request");
var resp = ProcessRequest(req);
Logging.Emit("request complete: supported={0}, exitcode={1}", resp.supported, resp.exitcode);
var tx = resp.Serialize();
nss.Write(tx, 0, tx.Length);
nss.Flush();
Logging.Emit("server written {0} bytes", tx.Length);

// deserialize message from msgbuf
var req = CClashMessage.Deserialize<CClashRequest>(msgbuf.ToArray());
cache.Setup();
var resp = ProcessRequest(req);
var tx = resp.Serialize();
nss.Write(tx, 0, tx.Length);
nss.Flush();
nss.WaitForPipeDrain();
nss.Disconnect();
Logging.Emit("request done");
}

// don't hog folders
cache.Finished();
void NewServerThread(string cachedir)
{
var t = new Thread(new ParameterizedThreadStart(ConnectionThreadFn));
t.IsBackground = true;
serverThreads.Add(t);
var nss = new NamedPipeServerStream(MakePipeName(cachedir), PipeDirection.InOut, MaxServerThreads, PipeTransmissionMode.Message, PipeOptions.WriteThrough | PipeOptions.Asynchronous);
t.Start(nss);
Logging.Emit("server thread started");
}

public void Listen(string cachedir)
{
Environment.CurrentDirectory = mydocs;
var mtx = new Mutex(false, "cclash_serv_" + cachedir.ToLower().GetHashCode());
try
{

if (!mtx.WaitOne(1000))
{
quitnow = true;
Logging.Error("another server is already running");
return; // some other process is holding it!
}
}
catch (AbandonedMutexException)
{
Logging.Warning("previous instance did not exit cleanly!");
}
cache = new DirectCompilerCacheServer(cachedir);
Logging.Emit("starting server threads..");

nss.WaitForPipeDrain();
nss.Disconnect();
Logging.Emit("server disconnected..");
} catch (IOException) {
Logging.Warning("error on client pipe");
nss.Disconnect();
while (serverThreads.Count < MaxServerThreads)
{
NewServerThread(cachedir);
}

} catch (Exception e) {
Logging.Error("server exception {0}", e);
Stop();
}
} while (!quitnow);
Logging.Emit("server quitting");
// maintain the threadpool
while (!quitnow)
{
foreach (var t in serverThreads.ToArray())
{
if (t.Join(1000))
{
serverThreads.Remove(t);
NewServerThread(cachedir);
}
if (DateTime.Now.Subtract(lastRequest).TotalMinutes > QuitAfterIdleMinutes)
{
quitnow = true;
}
}
} catch (IOException ex) {
Logging.Emit("{0}", ex);
return;
} finally {
mtx.ReleaseMutex();
}
foreach (var t in serverThreads)
{
t.Join(2000);
}


Logging.Emit("server quitting");
mtx.ReleaseMutex();

}

public static string MakePipeName(string cachedir)
Expand All @@ -151,7 +226,7 @@ public CClashResponse ProcessRequest(CClashRequest req)
break;

case Command.Run:
cache.SetCompiler(req.compiler, req.workdir, new Dictionary<string,string>( req.envs ));
cache.SetCompilerEx(req.pid, req.compiler, req.workdir, new Dictionary<string,string>( req.envs ));
rv.exitcode = cache.CompileOrCache(req.argv);
System.IO.Directory.SetCurrentDirectory(mydocs);
rv.supported = true;
Expand Down
31 changes: 17 additions & 14 deletions CClash/CClashServerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,23 @@ void Connect()
if (ncs == null)
Open();

for (int i = 0; i < 2; i++)
try
{
try {
if (!ncs.IsConnected)
ncs.Connect(100);
ncs.ReadMode = PipeTransmissionMode.Message;
return;
} catch (IOException ex) {
Logging.Emit("error connecting {0}", ex.Message);
try { ncs.Dispose(); Open(); } catch { }
} catch (TimeoutException) {
}
if (!ncs.IsConnected)
ncs.Connect(100);
ncs.ReadMode = PipeTransmissionMode.Message;
return;
}
catch (IOException ex)
{
Logging.Emit("error connecting {0}", ex.Message);
try { ncs.Dispose(); Open(); }
catch { }
}
catch (TimeoutException)
{
}


// start the server, but lets not try to use it here, the next instance can
try {
Expand All @@ -59,11 +63,10 @@ void Connect()
p.StartInfo.WorkingDirectory = Environment.CurrentDirectory;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.Start();

throw new CClashWarningException("starting new server");
} catch (Exception e) {
Logging.Emit("error starting cclash server process", e.Message);
}
throw new CClashWarningException("failed to connect to server");
}

public ICacheInfo Stats
Expand Down Expand Up @@ -149,7 +152,7 @@ public CClashResponse Transact(CClashRequest req)
{
Connect();
CClashResponse resp = null;

req.pid = System.Diagnostics.Process.GetCurrentProcess().Id;
var txbuf = req.Serialize();

ncs.Write(txbuf, 0, txbuf.Length);
Expand Down
5 changes: 5 additions & 0 deletions CClash/CacheManifest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public static CacheManifest Deserialize(Stream stream)
/// </summary>
public string CommonHash { get; set; }

/// <summary>
/// Hash of the pre-existing PDB file before this object was created.
/// </summary>
public string EarlierPdbHash { get; set; }

/// <summary>
/// non-null if this entry was made by preprocessing the source
/// </summary>
Expand Down
Loading

0 comments on commit acfad81

Please sign in to comment.