This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 49459
Collapse All | Expand All

(-)loaders/src/org/openide/loaders/FolderChildren.java (-23 / +4 lines)
Lines 175-208 Link Here
175
        }
175
        }
176
        return super.findChild(name);
176
        return super.findChild(name);
177
    }
177
    }
178
    
178
179
180
179
    /**
181
    /**
180
     * This code could probably be replaced by
181
     * Children.MUTEX.isReadAccess, if such call would be added to Mutex
182
     * @return true if it is safe to wait (our thread is
182
     * @return true if it is safe to wait (our thread is
183
     *         not in Children.MUTEX.readAccess
183
     *         not in Children.MUTEX.readAccess
184
     */
184
     */
185
    private static boolean checkChildrenMutex() {
185
    private static boolean checkChildrenMutex() {
186
        class MutexChecker implements Runnable {
186
        return !Children.MUTEX.isReadAccess() && !Children.MUTEX.isWriteAccess ();
187
            public boolean checkReadOrWrite;
188
            public boolean inReadAccess = true;
189
            public boolean inWriteAccess = true;
190
            public void run () {
191
                if (checkReadOrWrite) {
192
                    inReadAccess = false;
193
                } else {
194
                    inWriteAccess = false;
195
                }
196
            }
197
        }
198
        MutexChecker test = new MutexChecker();
199
        // the code will run either immediatally or after we leave readAccess
200
        // section
201
        Children.MUTEX.postWriteRequest(test);
202
        test.checkReadOrWrite = true;
203
        Children.MUTEX.postReadRequest(test);
204
205
        return !test.inReadAccess && !test.inWriteAccess;
206
    }
187
    }
207
    
188
    
208
    /** Initializes the children.
189
    /** Initializes the children.
(-)src/org/openide/nodes/Children.java (-16 / +2 lines)
Lines 35-41 Link Here
35
     * access to children.
35
     * access to children.
36
     */
36
     */
37
    static final Mutex.Privileged PR = new Mutex.Privileged ();
37
    static final Mutex.Privileged PR = new Mutex.Privileged ();
38
    
38
39
    /** Lock for access to hierarchy of all node lists.
39
    /** Lock for access to hierarchy of all node lists.
40
    * Anyone who needs to ensure that there will not
40
    * Anyone who needs to ensure that there will not
41
    * be shared accesses to hierarchy nodes can use this
41
    * be shared accesses to hierarchy nodes can use this
Lines 473-493 Link Here
473
        } else {
473
        } else {
474
            // otherwise, if not initialize yet (arr.children) wait 
474
            // otherwise, if not initialize yet (arr.children) wait 
475
            // for the initialization to finish, but only if we can wait
475
            // for the initialization to finish, but only if we can wait
476
            
476
            if (MUTEX.isReadAccess() || initThread == Thread.currentThread()) {
477
            // we are not in ReadAccess
478
            // Children.MUTEX.isReadAccess, if such call would be added to Mutex
479
            class MutexChecker implements Runnable {
480
                public boolean inReadAccess = true;
481
                public void run () {
482
                    inReadAccess = false;
483
                }
484
            }
485
            MutexChecker test = new MutexChecker();
486
            // the code will run either immediatally or after we leave readAccess
487
            // section
488
            Children.MUTEX.postWriteRequest(test);
489
490
            if (test.inReadAccess || initThread == Thread.currentThread()) {
491
                // fail, we are in read access
477
                // fail, we are in read access
492
                if (cannotWorkBetter != null) {
478
                if (cannotWorkBetter != null) {
493
                    cannotWorkBetter[0] = true;
479
                    cannotWorkBetter[0] = true;
(-)src/org/openide/util/Mutex.java (-2 / +74 lines)
Lines 60-65 Link Here
60
* } catch (MutexException ex) {
60
* } catch (MutexException ex) {
61
*   throw (IOException)ex.getException ();
61
*   throw (IOException)ex.getException ();
62
* }
62
* }
63
*
64
* // check whether you are already in read access
65
* if (m.isReadAccess ()) {
66
*   // do your work
67
* }
63
* </PRE></code>
68
* </PRE></code>
64
*
69
*
65
* @author Ales Novak
70
* @author Ales Novak
Lines 67-72 Link Here
67
public final class Mutex extends Object {
72
public final class Mutex extends Object {
68
    /** Mutex that allows code to be synchronized with the AWT event dispatch thread. */
73
    /** Mutex that allows code to be synchronized with the AWT event dispatch thread. */
69
    public static final Mutex EVENT = new Mutex ();
74
    public static final Mutex EVENT = new Mutex ();
75
    /** this is used from tests to prevent upgrade from readAccess to writeAccess
76
     * by strictly throwing exception. Otherwise we just notify that using ErrorManager.
77
     */
78
    static boolean beStrict;
70
79
71
    // lock mode constants
80
    // lock mode constants
72
    /** Lock free */
81
    /** Lock free */
Lines 328-333 Link Here
328
        }
337
        }
329
    }
338
    }
330
339
340
    /** Tests whether this thread has already entered the mutex in read access.
341
     * If it returns true, calling <code>readAccess</code> 
342
     * will be executed immediatelly
343
     * without any blocking. 
344
     * Calling <code>postWriteAccess</code> will delay the execution
345
     * of its <code>Runnable</code> until a readAccess section is over
346
     * and calling <code>writeAccess</code> is strongly prohibited and will
347
     * result in a warning as a deadlock prone behaviour.
348
     *
349
     * @return true if the thread is in read access section
350
     * @since JST-PENDING
351
     */
352
    public boolean isReadAccess () {
353
        Thread t = Thread.currentThread();
354
        ThreadInfo info;
355
356
        synchronized (LOCK) {
357
            info = getThreadInfo(t);
358
            if (info != null) {
359
                if (info.counts[X] == 0) {
360
                    return true;
361
                }
362
            }
363
        }
364
        return false;
365
    }
366
    
367
    /** Tests whether this thread has already entered the mutex in write access.
368
     * If it returns true, calling <code>writeAccess</code> will be executed
369
     * immediatelly without any other blocking. <code>postReadAccess</code>
370
     * will be delayed until a write access runnable is over.
371
     *
372
     * @return true if the thread is in write access section
373
     * @since JST-PENDING
374
     */
375
    public boolean isWriteAccess () {
376
        Thread t = Thread.currentThread();
377
        ThreadInfo info;
378
379
        synchronized (LOCK) {
380
            info = getThreadInfo(t);
381
            if (info != null) {
382
                if (info.counts[S] == 0) {
383
                    return true;
384
                }
385
            }
386
        }
387
        return false;
388
    }
331
389
332
    /** Posts a read request. This request runs immediately iff
390
    /** Posts a read request. This request runs immediately iff
333
     * this Mutex is in the shared mode or this Mutex is not contended
391
     * this Mutex is in the shared mode or this Mutex is not contended
Lines 425-430 Link Here
425
                        if (info.forced) {
483
                        if (info.forced) {
426
                            info.forced = false;
484
                            info.forced = false;
427
                        } else {
485
                        } else {
486
                            if (requested == X && info.counts[S] > 0) {
487
                                IllegalStateException e = new IllegalStateException("WARNING: Going from readAccess to writeAccess, see #10778: http://www.netbeans.org/issues/show_bug.cgi?id=10778 "); // NOI18N
488
                                if (beStrict) {
489
                                    throw e;
490
                                }
491
                                ErrorManager.getDefault().notify(e);
492
                            }
493
                            
428
                            info.counts[requested]++;
494
                            info.counts[requested]++;
429
                            if ((requested == S) && (info.counts[requested] == 1)) {
495
                            if ((requested == S) && (info.counts[requested] == 1)) {
430
                                readersNo++;
496
                                readersNo++;
Lines 432-438 Link Here
432
                        }
498
                        }
433
                        return true;
499
                        return true;
434
                    } else if (canUpgrade(info.mode, requested)) { // S - X and no holders
500
                    } else if (canUpgrade(info.mode, requested)) { // S - X and no holders
435
                        IllegalStateException e = new IllegalStateException("WARNING: Going from readAccess to writeAccess, see #10778: http://www.netbeans.org/issues/show_bug.cgi?id=10778 ");
501
                        IllegalStateException e = new IllegalStateException("WARNING: Going from readAccess to writeAccess, see #10778: http://www.netbeans.org/issues/show_bug.cgi?id=10778 "); // NOI18N
502
                        if (beStrict) {
503
                            throw e;
504
                        }
436
                        ErrorManager.getDefault().notify(e);
505
                        ErrorManager.getDefault().notify(e);
437
506
438
                        info.mode = X;
507
                        info.mode = X;
Lines 447-453 Link Here
447
516
448
                        return true;
517
                        return true;
449
                    } else { // S - X and holders
518
                    } else { // S - X and holders
450
                        IllegalStateException e = new IllegalStateException("WARNING: Going from readAccess to writeAccess through queue, see #10778: http://www.netbeans.org/issues/show_bug.cgi?id=10778 ");
519
                        IllegalStateException e = new IllegalStateException("WARNING: Going from readAccess to writeAccess through queue, see #10778: http://www.netbeans.org/issues/show_bug.cgi?id=10778 "); // NOI18N
520
                        if (beStrict) {
521
                            throw e;
522
                        }
451
                        ErrorManager.getDefault().notify(e);
523
                        ErrorManager.getDefault().notify(e);
452
                        // chain follows
524
                        // chain follows
453
                    }
525
                    }
(-)test/unit/src/org/openide/util/MutexTest.java (-2 / +131 lines)
Lines 20-27 Link Here
20
import org.netbeans.junit.*;
20
import org.netbeans.junit.*;
21
21
22
public class MutexTest extends NbTestCase {
22
public class MutexTest extends NbTestCase {
23
    private Mutex.Privileged p;
23
    Mutex.Privileged p;
24
    private Mutex m;
24
    Mutex m;
25
    
25
    
26
    
26
    
27
    
27
    
Lines 44-49 Link Here
44
    protected void setUp () {
44
    protected void setUp () {
45
        p = new Mutex.Privileged ();
45
        p = new Mutex.Privileged ();
46
        m = new Mutex (p);
46
        m = new Mutex (p);
47
        Mutex.beStrict = true;
47
    }
48
    }
48
    
49
    
49
    public void testReadWriteRead() throws Exception {
50
    public void testReadWriteRead() throws Exception {
Lines 529-534 Link Here
529
        p.enterWriteAccess();
530
        p.enterWriteAccess();
530
        p.exitWriteAccess();
531
        p.exitWriteAccess();
531
    }
532
    }
533
    
534
    public void testNoWayToDoReadAndThenWrite () {
535
        class R implements Runnable {
536
            public void run () {
537
                m.writeAccess (this);
538
            }
539
        }
540
        
541
        try {
542
            m.readAccess (new R ());
543
            fail ("This is supposed to throw an IllegalStateException");
544
        } catch (IllegalStateException ex) {
545
            // ok, this is expected
546
        }
547
    }
548
549
    public void testNoWayToDoWriteThenReadAndThenWrite () {
550
        class R implements Runnable {
551
            public boolean second;
552
            public boolean end;
553
            public boolean ending;
554
            
555
            public void run () {
556
                if (end) {
557
                    ending = true;
558
                    return;
559
                }
560
                
561
                if (second) {
562
                    end = true;
563
                    m.writeAccess (this);
564
                } else {
565
                    second = true;
566
                    m.readAccess (this);
567
                }
568
            }
569
        }
570
        R r = new R ();
571
        try {
572
            m.writeAccess (r);
573
            fail ("This is supposed to throw an IllegalStateException");
574
        } catch (IllegalStateException ex) {
575
            // ok, this is expected
576
            assertTrue ("We were in the write access section", r.second);
577
            assertTrue ("We were before the writeAcess(this)", r.end);
578
            assertFalse ("We never reached ending", r.ending);
579
        }
580
    }
581
    
582
    public void testIsOrIsNotInReadOrWriteAccess () {
583
        new ReadWriteChecking ("No r/w", Boolean.FALSE, Boolean.FALSE).run ();
584
        m.readAccess (new ReadWriteChecking ("r but no w", Boolean.TRUE, Boolean.FALSE));
585
        m.writeAccess (new ReadWriteChecking ("w but no r", Boolean.FALSE, Boolean.TRUE));
586
        m.readAccess (new Runnable () {
587
            public void run () {
588
                m.postReadRequest (new ReadWriteChecking ("+r -w", Boolean.TRUE, Boolean.FALSE));
589
            }
590
        });
591
        m.readAccess (new Runnable () {
592
            public void run () {
593
                m.postWriteRequest (new ReadWriteChecking ("-r +w", Boolean.FALSE, Boolean.TRUE));
594
            }
595
        });
596
        m.writeAccess (new Runnable () {
597
            public void run () {
598
                m.postReadRequest (new ReadWriteChecking ("+r -w", Boolean.TRUE, Boolean.FALSE));
599
            }
600
        });
601
        m.writeAccess (new Runnable () {
602
            public void run () {
603
                m.postWriteRequest (new ReadWriteChecking ("-r +w", Boolean.FALSE, Boolean.TRUE));
604
            }
605
        });
606
        
607
        // write->read->test (downgrade from write to read)
608
        m.writeAccess (new Runnable () {
609
            public boolean second;
610
            
611
            public void run () {
612
                if (!second) {
613
                    second = true;
614
                    m.readAccess (this);
615
                    return;
616
                }
617
                
618
                class P implements Runnable {
619
                    public boolean exec;
620
                    public void run () {
621
                        exec = true;
622
                    }
623
                }
624
                P r = new P ();
625
                P w = new P ();
626
                m.postWriteRequest (w);
627
                m.postReadRequest (r);
628
                assertFalse ("Writer not executed", w.exec);
629
                assertFalse ("Reader not executed", r.exec);
630
                
631
                m.readAccess (new ReadWriteChecking ("+r no w", Boolean.FALSE, Boolean.FALSE));
632
            }
633
        });
634
        
635
        new ReadWriteChecking ("None at the end", Boolean.FALSE, Boolean.FALSE).run ();
636
    }
637
    
638
    private class ReadWriteChecking implements Runnable {
639
        public Boolean read;
640
        public Boolean write;
641
        public String msg;
642
643
        public ReadWriteChecking (String msg, Boolean read, Boolean write) {
644
            assertNotNull ("Msg cannot be null", msg);
645
            this.msg = msg;
646
            this.read = read;
647
            this.write = write;
648
        }
649
650
        protected void finalize () {
651
            assertNull ("Run method was not called!", msg);
652
        }
653
654
        public void run () {
655
            if (write != null) assertEquals (msg, write.booleanValue (), m.isWriteAccess ());
656
            if (read != null) assertEquals (msg, read.booleanValue (), m.isReadAccess ());
657
            msg = null;
658
        }
659
    }
660
    
532
    
661
    
533
    private static class State implements Runnable {
662
    private static class State implements Runnable {
534
        public int state;
663
        public int state;

Return to bug 49459