/* * sys_barrier.c - Access a POSIX barrier. * * authors Alain Greiner (2016,2017,2018,2019) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MKH. * * ALMOS-MKH is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-MKH is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-MKH; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include ////////////////////////////////// int sys_barrier( intptr_t vaddr, uint32_t operation, uint32_t count, intptr_t attr ) { error_t error; vseg_t * vseg; pthread_barrierattr_t k_attr; thread_t * this = CURRENT_THREAD; process_t * process = this->process; #if DEBUG_SYS_BARRIER || DEBUG_SYSCALLS_ERROR || CONFIG_INSTRUMENTATION_SYSCALLS uint64_t tm_start = hal_get_cycles(); #endif #if DEBUG_SYS_BARRIER if( DEBUG_SYS_BARRIER < tm_start ) printk("\n[%s] thread[%x,%x] enters for %s / count %d / cycle %d\n", __FUNCTION__, process->pid, this->trdid, sys_barrier_op_str(operation), count, (uint32_t)tm_start ); #endif // check vaddr in user vspace error = vmm_get_vseg( process , vaddr , &vseg ); if( error ) { #if DEBUG_SYSCALLS_ERROR if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start ) printk("\n[ERROR] in %s for %s : unmapped barrier %x / thread[%x,%x]\n", __FUNCTION__, sys_barrier_op_str(operation), vaddr, process->pid, this->trdid ); #endif this->errno = error; return -1; } // execute requested operation switch( operation ) { ////////////////// case BARRIER_INIT: { if( attr != 0 ) // QDT barrier required { error = vmm_get_vseg( process , attr , &vseg ); if( error ) { #if DEBUG_SYSCALLS_ERROR if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start ) printk("\n[ERROR] in %s for INIT : unmapped barrier attributes %x / thread[%x,%x]\n", __FUNCTION__ , attr , process->pid , this->trdid ); #endif this->errno = EINVAL; return -1; } // copy barrier attributes into kernel space hal_copy_from_uspace( XPTR( local_cxy , &k_attr ), (void *)attr, sizeof(pthread_barrierattr_t) ); if ( count != k_attr.x_size * k_attr.y_size *k_attr.nthreads ) { #if DEBUG_SYSCALLS_ERROR if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start ) printk("\n[ERROR] in %s for INIT : count (%d) != x_size (%d) * y_size (%d) * nthreads (%x)\n", __FUNCTION__, count, k_attr.x_size, k_attr.y_size, k_attr.nthreads ); #endif this->errno = EINVAL; return -1; } // call relevant system function error = generic_barrier_create( vaddr , count , &k_attr ); } else // simple barrier required { error = generic_barrier_create( vaddr , count , NULL ); } if( error ) { #if DEBUG_SYSCALLS_ERROR if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start ) printk("\n[ERROR] in %s for INIT : cannot create barrier %x / thread[%x,%x]\n", __FUNCTION__ , vaddr , process->pid , this->trdid ); #endif this->errno = ENOMEM; return -1; } break; } ////////////////// case BARRIER_WAIT: { xptr_t barrier_xp = generic_barrier_from_ident( vaddr ); if( barrier_xp == XPTR_NULL ) // user error { #if DEBUG_SYSCALLS_ERROR if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start ) printk("\n[ERROR] in %s for WAIT : barrier %x not registered / thread[%x,%x]\n", __FUNCTION__ , (intptr_t)vaddr , process->pid, this->trdid ); #endif this->errno = EINVAL; return -1; } else // success { generic_barrier_wait( barrier_xp ); } break; } ///////////////////// case BARRIER_DESTROY: { xptr_t barrier_xp = generic_barrier_from_ident( vaddr ); if( barrier_xp == XPTR_NULL ) // user error { #if DEBUG_SYSCALLS_ERROR if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start ) printk("\n[ERROR] in %s for DESTROY : barrier %x not registered / thread[%x,%x]\n", __FUNCTION__ , (intptr_t)vaddr , process->pid, this->trdid ); #endif this->errno = EINVAL; return -1; } else // success { generic_barrier_destroy( barrier_xp ); } break; } //////// default: { assert( __FUNCTION__, false, "illegal operation type <%x>", operation ); } } // end switch hal_fence(); #if (DEBUG_SYS_BARRIER || CONFIG_INSTRUMENTATION_SYSCALLS) uint64_t tm_end = hal_get_cycles(); #endif #if DEBUG_SYS_BARRIER if( DEBUG_SYS_BARRIER < tm_end ) printk("\n[%s] thread[%x,%x] exit for %s / cycle %d\n", __FUNCTION__, process->pid, this->trdid, sys_barrier_op_str(operation), (uint32_t)tm_end ); #endif #if CONFIG_INSTRUMENTATION_SYSCALLS hal_atomic_add( &syscalls_cumul_cost[SYS_BARRIER] , tm_end - tm_start ); hal_atomic_add( &syscalls_occurences[SYS_BARRIER] , 1 ); #endif return 0; } // end sys_barrier()