Пример #1
0
 /*
  * Wait for a thread to finish.
  *
  * 'mu_ref' is a lock we should use for the waiting; initially unlocked.
  * Same lock as passed to THREAD_EXIT.
  *
  * Returns TRUE for succesful wait, FALSE for timed out
  */
bool_t THREAD_WAIT( THREAD_T *ref, double secs , SIGNAL_T *signal_ref, MUTEX_T *mu_ref, volatile enum e_status *st_ref)
{
    struct timespec ts_store;
    const struct timespec *timeout= NULL;
    bool_t done;

    // Do timeout counting before the locks
    //
#if THREADWAIT_METHOD == THREADWAIT_TIMEOUT
    if (secs>=0.0)
#else // THREADWAIT_METHOD == THREADWAIT_CONDVAR
    if (secs>0.0)
#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
    {
        prepare_timeout( &ts_store, now_secs()+secs );
        timeout= &ts_store;
    }

#if THREADWAIT_METHOD == THREADWAIT_TIMEOUT
    /* Thread is joinable
    */
    if (!timeout) {
        PT_CALL( pthread_join( *ref, NULL /*ignore exit value*/ ));
        done= TRUE;
    } else {
        int rc= PTHREAD_TIMEDJOIN( *ref, NULL, timeout );
        if ((rc!=0) && (rc!=ETIMEDOUT)) {
            _PT_FAIL( rc, "PTHREAD_TIMEDJOIN", __FILE__, __LINE__-2 );
        }
        done= rc==0;
    }
#else // THREADWAIT_METHOD == THREADWAIT_CONDVAR
    /* Since we've set the thread up as PTHREAD_CREATE_DETACHED, we cannot
     * join with it. Use the cond.var.
    */
    (void) ref; // unused
    MUTEX_LOCK( mu_ref );
    
        // 'secs'==0.0 does not need to wait, just take the current status
        // within the 'mu_ref' locks
        //
        if (secs != 0.0) {
            while( *st_ref < DONE ) {
                if (!timeout) {
                    PT_CALL( pthread_cond_wait( signal_ref, mu_ref ));
                } else {
                    int rc= pthread_cond_timedwait( signal_ref, mu_ref, timeout );
                    if (rc==ETIMEDOUT) break;
                    if (rc!=0) _PT_FAIL( rc, "pthread_cond_timedwait", __FILE__, __LINE__-2 );
                }
            }
        }
        done= *st_ref >= DONE;  // DONE|ERROR_ST|CANCELLED

    MUTEX_UNLOCK( mu_ref );
#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
    return done;
  }
Пример #2
0
/*!
 * \brief Handle I2C I/O request.
 *
 * \todo There is no bus error checking at all...
 */
static int usb_i2c_io(struct usb_setup_data *req, uint8_t *buf, uint16_t *len)
{
	uint32_t reg32 __attribute__((unused));

	/* Interpret the request */
	uint8_t cmd = req->bRequest;
	uint8_t address = req->wIndex;
	uint8_t is_read = req->wValue & I2C_M_RD;
	uint8_t size = req->wLength;

	i2c_ctx_t ctx;

	i2c_ctx_init(&ctx, I2C1);

	/* We can ignore CMD_I2C_BEGIN, the hardware will work out which
	 * type of start condition to generate.
	 */
	PT_CALL(&ctx.leaf, i2c_ctx_start(&ctx));
	if (ctx.err)
		goto err;

	/* Send the address */
	PT_CALL(&ctx.leaf,
		i2c_ctx_sendaddr(&ctx, address, (is_read ? size : 0)));
	if (ctx.err)
		goto err;

	/* Perform the transaction */
	for (int i=0; i<size; i++) {
		PT_CALL(&ctx.leaf, is_read ? i2c_ctx_getdata(&ctx, buf + i)
					    : i2c_ctx_senddata(&ctx, buf[i]));
		if (ctx.err)
			goto err;
	}

	/* Stop the transaction if requested and this is a write transaction
	 * (reads are stopped automatically)
	 */
	if (cmd & CMD_I2C_END && !is_read) {
		PT_CALL(&ctx.leaf, i2c_ctx_stop(&ctx));
		if (ctx.err)
			goto err;
	}

	status = STATUS_ADDRESS_ACK;
	*len = (is_read ? size : 0);
	return USBD_REQ_HANDLED;

err:
	i2c_ctx_reset(&ctx);
	status = STATUS_ADDRESS_NACK;
	*len = 0;
	return USBD_REQ_HANDLED;
}
Пример #3
0
PT(ssd1306_printf,uint8_t row, uint8_t col, __code const char * format, ...) {
    va_list args;
    PT_B
    PT_LOCK(busy);
    va_start(args,format);
    i=0;
    printf_tiny(format,args);
    va_end(args);
    sbuf[16]=0; //force trancation
    PT_CALL(ssd1306_move,row,col);
    i=0;
    while(sbuf[i] != 0) {
        s_putc(sbuf[i++]);
        PT_CALL(ssd1306_tile,buf,9);
    }
    PT_UNLOCK(busy);
    PT_E
}
Пример #4
0
  bool_t SIGNAL_WAIT( SIGNAL_T *ref, pthread_mutex_t *mu, time_d abs_secs ) {
    if (abs_secs<0.0) {
        PT_CALL( pthread_cond_wait( ref, mu ) );  // infinite
    } else {
        int rc;
        struct timespec ts;

        assert( abs_secs != 0.0 );
        prepare_timeout( &ts, abs_secs );

        rc= pthread_cond_timedwait( ref, mu, &ts );

        if (rc==ETIMEDOUT) return FALSE;
        if (rc) { _PT_FAIL( rc, "pthread_cond_timedwait()", __FILE__, __LINE__ ); }
    }
    return TRUE;
  }
Пример #5
0
  void THREAD_CREATE( THREAD_T* ref, 
                      THREAD_RETURN_T (*func)( void * ),
                      void *data, int prio /* -2..+2 */ ) {
    pthread_attr_t _a;
    pthread_attr_t *a= &_a;
    struct sched_param sp;

    PT_CALL( pthread_attr_init(a) );

#ifndef PTHREAD_TIMEDJOIN
    // We create a NON-JOINABLE thread. This is mainly due to the lack of
    // 'pthread_timedjoin()', but does offer other benefits (s.a. earlier 
    // freeing of the thread's resources).
    //
    //PT_CALL( pthread_attr_setdetachstate(a,PTHREAD_CREATE_DETACHED) );
#endif

    // Use this to find a system's default stack size (DEBUG)
#if 0
  { size_t n; pthread_attr_getstacksize( a, &n );
    fprintf( stderr, "Getstack: %u\n", (unsigned int)n ); }
    	//  524288 on OS X
    	// 2097152 on Linux x86 (Ubuntu 7.04)
    	// 1048576 on FreeBSD 6.2 SMP i386
#endif

#if (defined _THREAD_STACK_SIZE) && (_THREAD_STACK_SIZE > 0)
    PT_CALL( pthread_attr_setstacksize( a, _THREAD_STACK_SIZE ) );
#endif
    
    bool_t normal= 
#if defined(PLATFORM_LINUX) && defined(LINUX_SCHED_RR)
        !sudo;          // with sudo, even normal thread must use SCHED_RR
#else
        prio == 0;      // create a default thread if
#endif
    if (!normal) {
        // NB: PThreads priority handling is about as twisty as one can get it
        //     (and then some). DON*T TRUST ANYTHING YOU READ ON THE NET!!!

        // "The specified scheduling parameters are only used if the scheduling
        //  parameter inheritance attribute is PTHREAD_EXPLICIT_SCHED."
        //
      #ifndef ANDROID  
		PT_CALL( pthread_attr_setinheritsched( a, PTHREAD_EXPLICIT_SCHED ) );
		#endif
        //---
        // "Select the scheduling policy for the thread: one of SCHED_OTHER 
        // (regular, non-real-time scheduling), SCHED_RR (real-time, 
        // round-robin) or SCHED_FIFO (real-time, first-in first-out)."
        //
        // "Using the RR policy ensures that all threads having the same
        // priority level will be scheduled equally, regardless of their activity."
        //
        // "For SCHED_FIFO and SCHED_RR, the only required member of the
        // sched_param structure is the priority sched_priority. For SCHED_OTHER,
        // the affected scheduling parameters are implementation-defined."
        //
        // "The priority of a thread is specified as a delta which is added to 
        // the priority of the process."
        //
        // ".. priority is an integer value, in the range from 1 to 127. 
        //  1 is the least-favored priority, 127 is the most-favored."
        //
        // "Priority level 0 cannot be used: it is reserved for the system."
        //
        // "When you use specify a priority of -99 in a call to 
        // pthread_setschedparam(), the priority of the target thread is 
        // lowered to the lowest possible value."
        //
        // ...

        // ** CONCLUSION **
        //
        // PThread priorities are _hugely_ system specific, and we need at
        // least OS specific settings. Hopefully, Linuxes and OS X versions
        // are uniform enough, among each other...
        //
#ifdef PLATFORM_OSX
        // AK 10-Apr-07 (OS X PowerPC 10.4.9):
        //
        // With SCHED_RR, 26 seems to be the "normal" priority, where setting
        // it does not seem to affect the order of threads processed.
        //
        // With SCHED_OTHER, the range 25..32 is normal (maybe the same 26,
        // but the difference is not so clear with OTHER).
        //
        // 'sched_get_priority_min()' and '..max()' give 15, 47 as the 
        // priority limits. This could imply, user mode applications won't
        // be able to use values outside of that range.
        //
        #define _PRIO_MODE SCHED_OTHER
        
        // OS X 10.4.9 (PowerPC) gives ENOTSUP for process scope
        //#define _PRIO_SCOPE PTHREAD_SCOPE_PROCESS

        #define _PRIO_HI  32    // seems to work (_carefully_ picked!)
        #define _PRIO_0   26    // detected
        #define _PRIO_LO   1    // seems to work (tested)

#elif defined(PLATFORM_LINUX)
        // (based on Ubuntu Linux 2.6.15 kernel)
        //
        // SCHED_OTHER is the default policy, but does not allow for priorities.
        // SCHED_RR allows priorities, all of which (1..99) are higher than
        // a thread with SCHED_OTHER policy.
        //
        // <http://kerneltrap.org/node/6080>
        // <http://en.wikipedia.org/wiki/Native_POSIX_Thread_Library>
        // <http://www.net.in.tum.de/~gregor/docs/pthread-scheduling.html>
        //
        // Manuals suggest checking #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING,
        // but even Ubuntu does not seem to define it.
        //
        #define _PRIO_MODE SCHED_RR
        
        // NTLP 2.5: only system scope allowed (being the basic reason why
        //           root privileges are required..)
        //#define _PRIO_SCOPE PTHREAD_SCOPE_PROCESS

        #define _PRIO_HI 99
        #define _PRIO_0  50
        #define _PRIO_LO 1

#elif defined(PLATFORM_BSD)
        //
        // <http://www.net.in.tum.de/~gregor/docs/pthread-scheduling.html>
        //
        // "When control over the thread scheduling is desired, then FreeBSD
        //  with the libpthread implementation is by far the best choice .."
        //
        #define _PRIO_MODE SCHED_OTHER
        #define _PRIO_SCOPE PTHREAD_SCOPE_PROCESS
        #define _PRIO_HI 31
        #define _PRIO_0  15
        #define _PRIO_LO 1

#elif defined(PLATFORM_CYGWIN)
	//
	// TBD: Find right values for Cygwin
	//
#else
        #error "Unknown OS: not implemented!"
#endif

#ifdef _PRIO_SCOPE
        PT_CALL( pthread_attr_setscope( a, _PRIO_SCOPE ) );
#endif
        PT_CALL( pthread_attr_setschedpolicy( a, _PRIO_MODE ) );

#define _PRIO_AN (_PRIO_0 + ((_PRIO_HI-_PRIO_0)/2) )
#define _PRIO_BN (_PRIO_LO + ((_PRIO_0-_PRIO_LO)/2) )

        sp.sched_priority= 
            (prio == +2) ? _PRIO_HI :
            (prio == +1) ? _PRIO_AN :
#if defined(PLATFORM_LINUX) && defined(LINUX_SCHED_RR)
            (prio == 0) ? _PRIO_0 :
#endif
            (prio == -1) ? _PRIO_BN : _PRIO_LO;

        PT_CALL( pthread_attr_setschedparam( a, &sp ) );
    }

    //---
    // Seems on OS X, _POSIX_THREAD_THREADS_MAX is some kind of system
    // thread limit (not userland thread). Actual limit for us is way higher.
    // PTHREAD_THREADS_MAX is not defined (even though man page refers to it!)
    //
# ifndef THREAD_CREATE_RETRIES_MAX
    // Don't bother with retries; a failure is a failure
    //
    { 
      int rc= pthread_create( ref, a, func, data );
      if (rc) _PT_FAIL( rc, "pthread_create()", __FILE__, __LINE__-1 );
    }
# else
# error "This code deprecated"
/*
    // Wait slightly if thread creation has exchausted the system
    //
    { uint_t retries;
    for( retries=0; retries<THREAD_CREATE_RETRIES_MAX; retries++ ) {

        int rc= pthread_create( ref, a, func, data );
            //
            // OS X / Linux:
            //    EAGAIN: ".. lacked the necessary resources to create
            //             another thread, or the system-imposed limit on the
            //             total number of threads in a process 
            //             [PTHREAD_THREADS_MAX] would be exceeded."
            //    EINVAL: attr is invalid
            // Linux:
            //    EPERM: no rights for given parameters or scheduling (no sudo)
            //    ENOMEM: (known to fail with this code, too - not listed in man)
            
        if (rc==0) break;   // ok!

        // In practise, exhaustion seems to be coming from memory, not a
        // maximum number of threads. Keep tuning... ;)
        //
        if (rc==EAGAIN) {
//fprintf( stderr, "Looping (retries=%d) ", retries );    // DEBUG

            // Try again, later.

            Yield();
        } else {
            _PT_FAIL( rc, "pthread_create()", __FILE__, __LINE__ );
        }
    }
    }
*/
# endif

    if (a) {
        PT_CALL( pthread_attr_destroy(a) );
    }
  }
Пример #6
0
 void SIGNAL_ALL( SIGNAL_T *ref ) {
   PT_CALL( pthread_cond_broadcast(ref) );     // wake up ALL waiting threads
 }
Пример #7
0
 void SIGNAL_ONE( SIGNAL_T *ref ) {
   PT_CALL( pthread_cond_signal(ref) );     // wake up ONE (or no) waiting thread
 }
Пример #8
0
 void SIGNAL_FREE( SIGNAL_T *ref ) {
   PT_CALL( pthread_cond_destroy(ref) );
 }
Пример #9
0
 void SIGNAL_INIT( SIGNAL_T *ref ) {
   PT_CALL( pthread_cond_init(ref,NULL /*attr*/) );
   }