001    /*----------------------------------------------------------------------------*/
002    /* Copyright (c) FIRST 2008-2012. All Rights Reserved.                        */
003    /* Open Source Software - may be modified and shared by FRC teams. The code   */
004    /* must be accompanied by the FIRST BSD license file in the root directory of */
005    /* the project.                                                               */
006    /*----------------------------------------------------------------------------*/
007    
008    package edu.wpi.first.wpilibj.communication;
009    
010    import com.sun.cldc.jna.Function;
011    import com.sun.cldc.jna.NativeLibrary;
012    import com.sun.cldc.jna.Pointer;
013    import com.sun.squawk.platform.posix.LibCUtil;
014    
015    /**
016     * Class exposing VxWorks semaphores.
017     * @author dtjones
018     */
019    public class Semaphore {
020        Pointer m_semaphore;
021    
022        /** Integer ms value indicating wait forever. */
023        public static final int WAIT_FOREVER = -1;
024    
025        static final int SEM_Q_FIFO                = 0x00; /* first in first out queue */
026        static final int SEM_Q_PRIORITY            = 0x01; /* priority sorted queue */
027        static final int SEM_DELETE_SAFE           = 0x04; /* owner delete safe (mutex opt.) */
028        static final int SEM_INVERSION_SAFE        = 0x08; /* no priority inversion (mutex opt.) */
029        static final int SEM_EVENTSEND_ERR_NOTIFY  = 0x10; /* notify when eventRsrcSend fails */
030        static final int SEM_INTERRUPTIBLE         = 0x20; /* interruptible on RTP signal */
031    
032        /**
033         * Options to create a semaphore with.
034         */
035        public static class Options {
036            int value = 0;
037            /**
038             * Set true to use a priority sorted queue, false to use first-in first-out
039             * @param priority
040             */
041            public void setPrioritySorted(boolean priority) {
042                if (priority) value |= SEM_Q_PRIORITY;
043                else value &= ~SEM_Q_PRIORITY;
044            }
045            /**
046             * Set whether or not the semaphore is delete safe.
047             * @param delSafe True to make the semaphore delete safe.
048             */
049            public void setDeleteSafe(boolean delSafe) {
050                if (delSafe) value |= SEM_DELETE_SAFE;
051                else value &= ~SEM_DELETE_SAFE;
052            }
053            /**
054             * Set whether the semaphore is inversion safe.
055             * @param invSafe True to set the semaphore to inversion safe.
056             */
057            public void setInversionSafe(boolean invSafe) {
058                if (invSafe) value |= SEM_INVERSION_SAFE;
059                else value &= ~SEM_INVERSION_SAFE;
060            }
061            /**
062             * Set whether the semaphore should notify on an error.
063             * @param errNot True to set error notify.
064             */
065            public void setErrorNotify(boolean errNot) {
066                if (errNot) value |= SEM_EVENTSEND_ERR_NOTIFY;
067                else value &= ~SEM_EVENTSEND_ERR_NOTIFY;
068            }
069            /**
070             * Set whether the semaphore is interruptable.
071             * @param intable True allows this semaphore to be interrupted.
072             */
073            public void setInterruptable(boolean intable) {
074                if (intable) value |= SEM_INTERRUPTIBLE;
075                else value &= ~SEM_INTERRUPTIBLE;
076            }
077        }
078    
079        private static Function semMCreateFn = NativeLibrary.getDefaultInstance().getFunction("semMCreate"); //SEM_ID         semMCreate    (int options);
080        private static Function semBCreateFn = NativeLibrary.getDefaultInstance().getFunction("semBCreate"); //SEM_ID         semBCreate    (int options, SEM_B_STATE initialState);
081        private static Function semCCreateFn = NativeLibrary.getDefaultInstance().getFunction("semCCreate"); //SEM_ID         semCCreate    (int options, int initialCount);
082        private static Function semDeleteFn = NativeLibrary.getDefaultInstance().getFunction("semDelete");  //STATUS          semDelete     (SEM_ID semId);
083        private static Function semFlushFn = NativeLibrary.getDefaultInstance().getFunction("semFlush");   //STATUS           semFlush      (SEM_ID semId);
084        private static Function semGiveFn = NativeLibrary.getDefaultInstance().getFunction("semGive");    //STATUS    semGive       (SEM_ID semId);
085        private static Function semTakeFn = NativeLibrary.getDefaultInstance().getFunction("semTake");    //STATUS    semTake       (SEM_ID semId, int timeout);
086        private static Function semTakeBlockingFn = NativeLibrary.getDefaultInstance().getBlockingFunction("semTake");    //STATUS    semTake       (SEM_ID semId, int timeout);
087    //    private static Function semOpenFn = NativeLibrary.getDefaultInstance().getFunction("semOpen");    //SEM_ID          semOpen       (const char * name, SEM_TYPE type, int initState, int options, int mode, void * context);
088    //    private static Function semInfoGetFn = NativeLibrary.getDefaultInstance().getFunction("semInfoGet"); //STATUS       semInfoGet    (SEM_ID semId, SEM_INFO *pInfo);
089        private static Function semCloseFn = NativeLibrary.getDefaultInstance().getFunction("semClose");   //STATUS semClose (SEM_ID semId);
090    //    private static Function semUnlinkFn = NativeLibrary.getDefaultInstance().getFunction("semUnlink");  //STATUS semUnlink (const char * name);
091    
092        private void checkStatus (int status) throws SemaphoreException{
093            if (status != 0) {
094                throw new SemaphoreException(LibCUtil.errno());
095            }
096        }
097    
098        /**
099         * Create a new semaphore.
100         * @param options The options to create the semaphore with.
101         */
102        public Semaphore (Options options) {
103            m_semaphore = new Pointer(semMCreateFn.call1(options.value), 0);
104        }
105    
106        /**
107         * Create a semaphore with the given initial state.
108         * @param options The options to create the semaphore with.
109         * @param initialState The initial state for the semaphore to have.
110         */
111        public Semaphore (Options options, boolean initialState) {
112            m_semaphore = new Pointer(semBCreateFn.call2(options.value,initialState?1:0), 0);
113        }
114    
115        /**
116         * Create a counting semaphore with the given value.
117         * @param options The options to create the semaphore with.
118         * @param count The initial count for the semaphore to hold.
119         */
120        public Semaphore (Options options, int count) {
121            m_semaphore = new Pointer(semCCreateFn.call2(options.value, count), 0);
122        }
123    
124        /**
125         * Get the pointer to the native semaphore.
126         * @return Pointer to the native semaphore.
127         */
128        public Pointer getPointer() {
129            return m_semaphore;
130        }
131    
132        /**
133         * Unblock every task that is blocked by the semaphore.
134         */
135        public void flush() throws SemaphoreException{
136            checkStatus(semFlushFn.call1(m_semaphore));
137        }
138    
139        /**
140         * Release the semaphore.
141         */
142        public void give() throws SemaphoreException{
143            checkStatus(semGiveFn.call1(m_semaphore));
144        }
145    
146        /**
147         * Take the semaphore. Block for timeout milliseconds.
148         * @param timeout The maximum time in milliseconds to block for the semaphore.
149         * @throws SemaphoreException if the lock can't be take in timeout seconds, or some other semaphore error condition occurs.
150         */
151        public void takeMillis(int timeout) throws SemaphoreException{
152            checkStatus(semTakeBlockingFn.call2(m_semaphore, timeout));
153        }
154    
155        /**
156         * Take the semaphore. Block forever until semaphore is available.
157         * @throws SemaphoreException if some semaphore error condition occurs.
158         */
159        public void takeForever() throws SemaphoreException{
160            takeMillis(WAIT_FOREVER);
161        }
162    
163        /*
164         * Non-blocking version of take(). Try to take the Semaphore.
165         * 
166         * @return If succeeded return true, otherwise return false.
167         * @throws SemaphoreException if some semaphore error condition occurs.
168         */
169        public boolean tryTake() throws SemaphoreException{
170            int result = semTakeFn.call2(m_semaphore, 0);
171            if (result == 0) {
172                return true;
173            } else {
174                int errno = LibCUtil.errno();
175                if (errno == SemaphoreException.S_objLib_OBJ_UNAVAILABLE) {
176                    return false;
177                } else {
178                    throw new SemaphoreException(errno);
179                }
180            }
181        }
182    
183        /**
184         * Close the semaphore.
185         */
186        public void close () throws SemaphoreException{
187            checkStatus(semCloseFn.call1(m_semaphore));
188        }
189    
190        /**
191         * Release all resources associated with the semaphore.
192         */
193        public void free () throws SemaphoreException{
194            checkStatus(semDeleteFn.call1(m_semaphore));
195        }
196    }