| Index: content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
|
| diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
|
| index 75d0c2e9ebaf373fd0eb3f3c93afaa96261f3661..fe929a7d537c519e0421796a45558ef5ab2596f9 100644
|
| --- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
|
| +++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
|
| @@ -49,7 +49,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
| */
|
| @JNINamespace("content")
|
| public class ChildProcessLauncher {
|
| - private static final String TAG = "cr.ChildProcLauncher";
|
| + private static final String TAG = "ChildProcLauncher";
|
|
|
| static final int CALLBACK_FOR_UNKNOWN_PROCESS = 0;
|
| static final int CALLBACK_FOR_GPU_PROCESS = 1;
|
| @@ -236,6 +236,7 @@ public class ChildProcessLauncher {
|
|
|
| private static class PendingSpawnQueue {
|
| // The list of pending process spawn requests and its lock.
|
| + // Operations on this queue must be atomical w.r.t. free connections updates.
|
| private static Queue<PendingSpawnData> sPendingSpawns =
|
| new LinkedList<PendingSpawnData>();
|
| static final Object sPendingSpawnsLock = new Object();
|
| @@ -244,27 +245,24 @@ public class ChildProcessLauncher {
|
| * Queue up a spawn requests to be processed once a free service is available.
|
| * Called when a spawn is requested while we are at the capacity.
|
| */
|
| - public void enqueue(final PendingSpawnData pendingSpawn) {
|
| - synchronized (sPendingSpawnsLock) {
|
| - sPendingSpawns.add(pendingSpawn);
|
| - }
|
| + public void enqueueLocked(final PendingSpawnData pendingSpawn) {
|
| + assert Thread.holdsLock(sPendingSpawnsLock);
|
| + sPendingSpawns.add(pendingSpawn);
|
| }
|
|
|
| /**
|
| * Pop the next request from the queue. Called when a free service is available.
|
| * @return the next spawn request waiting in the queue.
|
| */
|
| - public PendingSpawnData dequeue() {
|
| - synchronized (sPendingSpawnsLock) {
|
| - return sPendingSpawns.poll();
|
| - }
|
| + public PendingSpawnData dequeueLocked() {
|
| + assert Thread.holdsLock(sPendingSpawnsLock);
|
| + return sPendingSpawns.poll();
|
| }
|
|
|
| /** @return the count of pending spawns in the queue */
|
| - public int size() {
|
| - synchronized (sPendingSpawnsLock) {
|
| - return sPendingSpawns.size();
|
| - }
|
| + public int sizeLocked() {
|
| + assert Thread.holdsLock(sPendingSpawnsLock);
|
| + return sPendingSpawns.size();
|
| }
|
| }
|
|
|
| @@ -416,9 +414,7 @@ public class ChildProcessLauncher {
|
| ThreadUtils.postOnUiThreadDelayed(new Runnable() {
|
| @Override
|
| public void run() {
|
| - getConnectionAllocator(conn.isInSandbox()).free(conn);
|
| -
|
| - final PendingSpawnData pendingSpawn = sPendingSpawnQueue.dequeue();
|
| + final PendingSpawnData pendingSpawn = freeConnectionAndDequeuePending(conn);
|
| if (pendingSpawn != null) {
|
| new Thread(new Runnable() {
|
| @Override
|
| @@ -434,6 +430,13 @@ public class ChildProcessLauncher {
|
| }, FREE_CONNECTION_DELAY_MILLIS);
|
| }
|
|
|
| + private static PendingSpawnData freeConnectionAndDequeuePending(ChildProcessConnection conn) {
|
| + synchronized (PendingSpawnQueue.sPendingSpawnsLock) {
|
| + getConnectionAllocator(conn.isInSandbox()).free(conn);
|
| + return sPendingSpawnQueue.dequeueLocked();
|
| + }
|
| + }
|
| +
|
| // Represents an invalid process handle; same as base/process/process.h kNullProcessHandle.
|
| private static final int NULL_PROCESS_HANDLE = 0;
|
|
|
| @@ -693,14 +696,16 @@ public class ChildProcessLauncher {
|
| if (allocatedConnection == null) {
|
| boolean alwaysInForeground = false;
|
| if (callbackType == CALLBACK_FOR_GPU_PROCESS) alwaysInForeground = true;
|
| - allocatedConnection = allocateBoundConnection(
|
| - context, commandLine, inSandbox, alwaysInForeground);
|
| - if (allocatedConnection == null) {
|
| - Log.d(TAG, "Allocation of new service failed. Queuing up pending spawn.");
|
| - sPendingSpawnQueue.enqueue(new PendingSpawnData(context, commandLine,
|
| - childProcessId, filesToBeMapped, clientContext, callbackType,
|
| - inSandbox));
|
| - return;
|
| + synchronized (PendingSpawnQueue.sPendingSpawnsLock) {
|
| + allocatedConnection = allocateBoundConnection(
|
| + context, commandLine, inSandbox, alwaysInForeground);
|
| + if (allocatedConnection == null) {
|
| + Log.d(TAG, "Allocation of new service failed. Queuing up pending spawn.");
|
| + sPendingSpawnQueue.enqueueLocked(new PendingSpawnData(context, commandLine,
|
| + childProcessId, filesToBeMapped, clientContext,
|
| + callbackType, inSandbox));
|
| + return;
|
| + }
|
| }
|
| }
|
|
|
| @@ -890,8 +895,10 @@ public class ChildProcessLauncher {
|
| */
|
| @VisibleForTesting
|
| static void enqueuePendingSpawnForTesting(Context context, String[] commandLine) {
|
| - sPendingSpawnQueue.enqueue(new PendingSpawnData(context, commandLine, 1,
|
| - new FileDescriptorInfo[0], 0, CALLBACK_FOR_RENDERER_PROCESS, true));
|
| + synchronized (PendingSpawnQueue.sPendingSpawnsLock) {
|
| + sPendingSpawnQueue.enqueueLocked(new PendingSpawnData(context, commandLine, 1,
|
| + new FileDescriptorInfo[0], 0, CALLBACK_FOR_RENDERER_PROCESS, true));
|
| + }
|
| }
|
|
|
| /** @return the count of sandboxed connections managed by the allocator */
|
| @@ -910,7 +917,9 @@ public class ChildProcessLauncher {
|
| /** @return the count of pending spawns in the queue */
|
| @VisibleForTesting
|
| static int pendingSpawnsCountForTesting() {
|
| - return sPendingSpawnQueue.size();
|
| + synchronized (PendingSpawnQueue.sPendingSpawnsLock) {
|
| + return sPendingSpawnQueue.sizeLocked();
|
| + }
|
| }
|
|
|
| /**
|
|
|