public void Run()
            {
                Implementation impl;
                var            rd = "";

                while (true)
                {
                    if (!impls.TryTake(out impl))
                    {
                        break;
                    }

                    while (!resources.TryTake(out rd))
                    {
                        Thread.Sleep(100);
                    }

                    sem.WaitOne();

                    var wd = Path.Combine(rd, impl.Name); // create new directory for each entrypoint

                    Directory.CreateDirectory(wd);        // create new directory for each entrypoint
                    RemoteExec.CleanDirectory(wd);
                    var     pruneFile = Path.Combine(wd, "pruneSlice.bpl");
                    Program newprogram;

                    // lock because Parsing a program is not thread-safe
                    lock (fslock)
                    {
                        BoogieUtil.PrintProgram(program, pruneFile);           // dump original program (so that each entrypoint has its own copy of program)
                        newprogram = BoogieUtil.ReadAndOnlyResolve(pruneFile); // entrypoint's copy of the program
                    }

                    // slice the program by entrypoints
                    Program shallowP = pruneDeepProcs(newprogram, ref edges, impl.Name, approximationDepth, implNames);
                    BoogieUtil.pruneProcs(shallowP,
                                          shallowP.TopLevelDeclarations.OfType <Procedure>()
                                          .Where(proc => BoogieUtil.checkAttrExists("entrypoint", proc.Attributes))
                                          .Select(proc => proc.Name)
                                          .FirstOrDefault());

                    File.Delete(pruneFile);
                    lock (fslock)
                    {
                        BoogieUtil.PrintProgram(shallowP, pruneFile); // dump sliced program
                    }

                    sem.Release();

                    if (Driver.createEntryPointBplsOnly)
                    {
                        Console.WriteLine("Skipping AVN run for {0} given /createEntrypointBplsOnly", impl.Name);
                        resources.Add(rd);
                        continue;
                    }
                    if (!remotedirs.Contains(rd))
                    {
                        Console.WriteLine("Running entrypoint {0} locally {{", impl.Name);

                        if (deadlineReached)
                        {
                            return;
                        }

                        // spawn the job -- local
                        var output = RemoteExec.run(wd, avnPath, string.Format("\"{0}\" {1}", pruneFile, avnArgs));

                        lock (fslock)
                        {
                            // delete temp files
                            if (!keepFiles)
                            {
                                var files = System.IO.Directory.GetFiles(wd, "*.bpl");
                                foreach (var f in files)
                                {
                                    System.IO.File.Delete(f);
                                }
                            }

                            using (StreamWriter sw = new StreamWriter(Path.Combine(wd, "stdout.txt")))
                                output.Iter(s => sw.WriteLine("{0}", s));
                        }

                        Console.WriteLine("Running entrypoint {0} locally }}", impl.Name);
                    }
                    else
                    {
                        // spawn the job -- remote
                        if (psexecPath == null)
                        {
                            throw new FileNotFoundException("Cannot find PSEXEC!");
                        }

                        // find the name of the machine from the remote folder name
                        var machine    = "";
                        var remoteroot = RemoteExec.GetRemoteFolder(rd, out machine);

                        Console.WriteLine("Running entrypoint {0} on {1} {{", impl.Name, machine);

                        // psexec machine -w remoteroot\impl remoteroot\fastavn\fastavn.exe remoteroot args
                        wd = Path.Combine(remoteroot, impl.Name);
                        var cmd = string.Format("{0} -w {1} {2} {3} {4}", machine, wd, Path.Combine(remoteroot, "fastavn", "AngelicVerifierNull.exe"),
                                                "pruneSlice.bpl", avnArgs);
                        //Console.WriteLine("PSEXEC Running: {0}", cmd);

                        if (deadlineReached)
                        {
                            return;
                        }

                        var output = RemoteExec.run(Directory.GetCurrentDirectory(), psexecPath, cmd);

                        lock (fslock)
                        {
                            // delete temp files
                            var td = Path.Combine(rd, impl.Name);
                            if (debug)
                            {
                                Console.WriteLine("Getting files in directory: {0}", td);
                            }
                            var files = System.IO.Directory.GetFiles(td, "*.bpl");
                            foreach (var f in files)
                            {
                                if (debug)
                                {
                                    Console.WriteLine("Deleting {0}", f);
                                }
                                System.IO.File.Delete(f);
                            }

                            // copy the results back
                            var ld = Path.Combine(Directory.GetCurrentDirectory(), impl.Name);
                            Directory.CreateDirectory(ld);
                            RemoteExec.CleanDirectory(ld);
                            RemoteExec.CopyFolder(rd, Directory.GetCurrentDirectory(), impl.Name, true);

                            using (StreamWriter sw = new StreamWriter(Path.Combine(ld, "stdout.txt")))
                                output.Iter(s => sw.WriteLine("{0}", s));
                        }

                        Console.WriteLine("Running entrypoint {0} on {1} }}", impl.Name, machine);
                    }

                    lock (fslock)
                    {
                        // collect and merge bugs
                        var bugs = collectBugs(Path.Combine(Directory.GetCurrentDirectory(), impl.Name, bugReportFileName));
                        bugs.Iter(b =>
                        {
                            if (!mergedBugs.ContainsKey(b))
                            {
                                mergedBugs[b] = 0;
                            }
                            mergedBugs[b] += 1;
                        });
                        Utils.Print(string.Format("Bugs found so far: {0}", mergedBugs.Count));

                        resources.Add(rd);
                    }
                }
            }
        /// <summary>
        /// Run AVN binary on sliced programs
        /// </summary>
        /// <param name="prog">Original program</param>
        /// <param name="approximationDepth">Depth k beyond which angelic approximation is applied</param>
        private static void sliceAndRunAVN(Program prog, int approximationDepth, HashSet <string> epNames)
        {
            edges = buildCallGraph(prog);

            // Create a list of resources
            var worklist = new ConcurrentBag <string>();

            for (int i = 0; i < numThreads; i++)
            {
                worklist.Add(Directory.GetCurrentDirectory());
            }
            if (config != null)
            {
                foreach (var r in config.RemoteRoots)
                {
                    remotedirs.Add(r.dir);
                    for (int i = 0; i < r.Threads; i++)
                    {
                        worklist.Add(r.dir);
                    }
                }
            }

            worklist = Shuffle(worklist);

            // Install FASTAVN
            foreach (var rd in remotedirs)
            {
                Console.WriteLine("Installing on {0}", rd);
                Directory.CreateDirectory(Path.Combine(rd, "fastavn"));
                RemoteExec.CopyFolder(Path.GetDirectoryName(avnPath), Path.Combine(rd, "fastavn"), true);
            }

            // max threads
            var threadsToSpawn = worklist.Count;

            // semaphore for limiting at most numThreads threads running at one time on local machine
            var sem = new Semaphore(numThreads, numThreads);

            // entrypoints
            var entrypoints = new ConcurrentBag <Implementation>(prog.TopLevelDeclarations.OfType <Implementation>()
                                                                 .Where(impl => epNames.Contains(impl.Name)));

            // deadline
            if (deadline > 0)
            {
                deadline = deadline - (int)((DateTime.Now - startingTime).TotalSeconds + 0.5);
                if (deadline < 0)
                {
                    deadline = 1;
                }
            }

            if (deadline > 100)
            {
                var timeouttask = new System.Threading.Tasks.Task(() =>
                {
                    System.Threading.Thread.Sleep((deadline - 100) * 1000);
                    Console.WriteLine("FastAvn deadline reached; consolidating results");

                    deadlineReached = true;
                    KillSpawnedProcesses();

                    // Sleep for 2 seconds
                    System.Threading.Thread.Sleep(2 * 1000);

                    // collate bugs
                    lock (fslock)
                    {
                        if (printingOutput)
                        {
                            return;
                        }
                        printingOutput = true;
                        printBugs(ref mergedBugs, epNames.Count);
                        mergeBugs(epNames);
                    }

                    // Kill self
                    Process.GetCurrentProcess().Kill();
                });
                timeouttask.Start();
            }
            else if (deadline != 0)
            {
                Console.WriteLine("Ignoring small deadline of {0} seconds", deadline);
            }

            var threads = new List <Thread>();

            for (int i = 0; i < threadsToSpawn; i++)
            {
                var w = new Worker(prog, entrypoints, worklist, sem);
                threads.Add(new Thread(new ThreadStart(w.Run)));
            }

            threads.Iter(t => t.Start());
            threads.Iter(t => t.Join());

            if (Driver.createEntryPointBplsOnly)
            {
                Console.WriteLine("Early exit due to /createEntryPointBplsOnly");
                return;
            }
            lock (fslock)
            {
                if (printingOutput)
                {
                    return;
                }
                printingOutput = true;
                printBugs(ref mergedBugs, epNames.Count);
                mergeBugs(epNames);
            }
        }