1   /*
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2026, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v2.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  
15  package ch.qos.logback.classic;
16  
17  import java.util.concurrent.CyclicBarrier;
18  
19  import org.junit.jupiter.api.Disabled;
20  import org.junit.jupiter.api.Test;
21  
22  import ch.qos.logback.core.testUtil.AbstractMultiThreadedHarness;
23  import ch.qos.logback.core.testUtil.RunnableWithCounterAndDone;
24  import ch.qos.logback.core.status.testUtil.StatusChecker;
25  import org.junit.jupiter.api.Timeout;
26  
27  @Disabled
28  public class LoggerContextConcurrentResetTest {
29      static int CONCURRENT_RESET_THREAD_COUNT = 10;
30  
31      // see http://jira.qos.ch/browse/LOGBACK-397
32      @Test
33      @Timeout(value = 1)
34      public void concurrentReset() throws InterruptedException {
35          LoggerContext loggerContext = new LoggerContext();
36          CyclicBarrier cyclicBarrier = new CyclicBarrier(CONCURRENT_RESET_THREAD_COUNT);
37          StatusChecker statusChecker = new StatusChecker(loggerContext);
38          int desiredResetCount = 100;
39          RunnableWithCounterAndDone[] runnableArray = buildRunnableArray(loggerContext, cyclicBarrier);
40          Harness harness = new Harness((Resetter) runnableArray[0], desiredResetCount);
41          harness.execute(runnableArray);
42          statusChecker.assertIsErrorFree();
43      }
44  
45      class Harness extends AbstractMultiThreadedHarness {
46          int desiredResetCount;
47          Resetter resetter;
48  
49          Harness(Resetter resetter, int desiredResetCount) {
50              this.resetter = resetter;
51              this.desiredResetCount = desiredResetCount;
52          }
53  
54          public void waitUntilEndCondition() throws InterruptedException {
55              while (resetter.getCounter() < desiredResetCount) {
56                  Thread.yield();
57              }
58          }
59      }
60  
61      static class GetLoggerRunnable extends RunnableWithCounterAndDone {
62  
63          final int burstLength = 30;
64          LoggerContext loggerContext;
65          CyclicBarrier cyclicBarrier;
66          String nameSuffix;
67  
68          GetLoggerRunnable(LoggerContext loggerContext, CyclicBarrier cyclicBarrier, String nameSuffix) {
69              this.loggerContext = loggerContext;
70              this.cyclicBarrier = cyclicBarrier;
71              this.nameSuffix = nameSuffix;
72          }
73  
74          public void run() {
75              try {
76                  cyclicBarrier.await();
77              } catch (Exception e) {
78              }
79  
80              while (!isDone()) {
81                  long i = counter % burstLength;
82                  loggerContext.getLogger("org.bla." + nameSuffix + ".x" + i);
83                  counter++;
84                  if (i == 0) {
85                      Thread.yield();
86                  }
87              }
88          }
89      }
90  
91      static class Resetter extends RunnableWithCounterAndDone {
92          LoggerContext loggerContext;
93          CyclicBarrier cyclicBarrier;
94          public int resetCount = 0;
95  
96          Resetter(LoggerContext loggerContext, CyclicBarrier cyclicBarrier) {
97              this.loggerContext = loggerContext;
98              this.cyclicBarrier = cyclicBarrier;
99          }
100 
101         public void run() {
102             try {
103                 cyclicBarrier.await();
104             } catch (Exception e) {
105             }
106             while (!isDone()) {
107                 loggerContext.reset();
108                 counter++;
109                 Thread.yield();
110             }
111         }
112     }
113 
114     private RunnableWithCounterAndDone[] buildRunnableArray(LoggerContext loggerContext, CyclicBarrier cyclicBarrier) {
115         RunnableWithCounterAndDone[] rArray = new RunnableWithCounterAndDone[CONCURRENT_RESET_THREAD_COUNT];
116         rArray[0] = new Resetter(loggerContext, cyclicBarrier);
117         for (int i = 1; i < CONCURRENT_RESET_THREAD_COUNT; i++) {
118             rArray[i] = new GetLoggerRunnable(loggerContext, cyclicBarrier, "mouse-" + i);
119         }
120         return rArray;
121     }
122 }