• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

AbstractBuffer.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 #include "ink_config.h"
00025 #include <assert.h>
00026 #include <string.h>
00027 #include "AbstractBuffer.h"
00028 /* #include "CacheAtomic.h" */
00029 #include "ink_align.h"
00030 
00031 
00032 /*-------------------------------------------------------------------------
00033   -------------------------------------------------------------------------*/
00034 
00035 ABError AbstractBuffer::checkout_write(int *write_offset, int write_size, uint64_t retries)
00036 {
00037   VolatileState
00038     old_vs;
00039   VolatileState
00040     new_vs;
00041 
00042   write_size = INK_ALIGN(write_size, alignment);
00043 
00044   // Initialize the buffer if it currently isn't in use.
00045   old_vs = vs;
00046   new_vs = old_vs;
00047 
00048   if (new_vs.s.state == AB_STATE_UNUSED) {
00049     new_vs.s.state = AB_STATE_INITIALIZING;
00050     if (switch_state(old_vs, new_vs)) {
00051       vs_history[AB_STATE_INITIALIZING] = old_vs;
00052       initialize();
00053     }
00054   }
00055 
00056   while (retries-- > 0) {
00057     old_vs = vs;
00058     new_vs = old_vs;
00059 
00060     if (new_vs.s.state != AB_STATE_READ_WRITE) {
00061       return AB_ERROR_STATE;
00062     }
00063 
00064     if ((uint32_t) (new_vs.s.offset + write_size) > (uint32_t) size) {
00065       new_vs.s.state = AB_STATE_READ_ONLY;
00066       if (switch_state(old_vs, new_vs)) {
00067         vs_history[AB_STATE_READ_ONLY] = old_vs;
00068         full();
00069       }
00070       return AB_ERROR_FULL;
00071     }
00072 
00073     *write_offset = new_vs.s.offset;
00074     new_vs.s.offset += write_size;
00075     new_vs.s.writer_count += 1;
00076 
00077     if (switch_state(old_vs, new_vs)) {
00078       ink_assert((*write_offset + write_size) <= size);
00079       return AB_ERROR_OK;
00080     }
00081   }
00082 
00083   return AB_ERROR_BUSY;
00084 }
00085 
00086 /*-------------------------------------------------------------------------
00087   -------------------------------------------------------------------------*/
00088 
00089 ABError AbstractBuffer::checkout_read(int read_offset, int read_size)
00090 {
00091   VolatileState
00092     old_vs;
00093   VolatileState
00094     new_vs;
00095 
00096   do {
00097     old_vs = vs;
00098     new_vs = old_vs;
00099 
00100     if ((new_vs.s.state != AB_STATE_READ_WRITE) &&
00101         (new_vs.s.state != AB_STATE_READ_ONLY) && (new_vs.s.state != AB_STATE_FLUSH)) {
00102       return AB_ERROR_STATE;
00103     }
00104 
00105     if ((uint32_t) (read_offset + read_size) > new_vs.s.offset) {
00106       return AB_ERROR_OFFSET;
00107     }
00108 
00109     new_vs.s.reader_count += 1;
00110   } while (!switch_state(old_vs, new_vs));
00111 
00112   return AB_ERROR_OK;
00113 }
00114 
00115 /*-------------------------------------------------------------------------
00116   -------------------------------------------------------------------------*/
00117 
00118 ABError AbstractBuffer::checkin_write(int write_offset)
00119 {
00120   VolatileState
00121     old_vs;
00122   VolatileState
00123     new_vs;
00124 
00125   do {
00126     old_vs = vs;
00127     new_vs = old_vs;
00128 
00129     ink_assert(new_vs.s.writer_count > 0);
00130     ink_assert((new_vs.s.state == AB_STATE_READ_WRITE) || (new_vs.s.state == AB_STATE_READ_ONLY));
00131     ink_assert((uint32_t) write_offset < new_vs.s.offset);
00132 
00133     new_vs.s.writer_count -= 1;
00134   } while (!switch_state(old_vs, new_vs));
00135 
00136   old_vs = vs;
00137   new_vs = old_vs;
00138 
00139   while ((new_vs.s.state == AB_STATE_READ_ONLY) && (new_vs.s.writer_count == 0)) {
00140     new_vs.s.state = AB_STATE_FLUSH;
00141     if (switch_state(old_vs, new_vs)) {
00142       vs_history[AB_STATE_FLUSH] = old_vs;
00143       flush();
00144       break;
00145     }
00146 
00147     old_vs = vs;
00148     new_vs = old_vs;
00149   }
00150 
00151   return AB_ERROR_OK;
00152 }
00153 
00154 /*-------------------------------------------------------------------------
00155   -------------------------------------------------------------------------*/
00156 
00157 ABError AbstractBuffer::checkin_read(int read_offset)
00158 {
00159   VolatileState
00160     old_vs;
00161   VolatileState
00162     new_vs;
00163 
00164   do {
00165     old_vs = vs;
00166     new_vs = old_vs;
00167 
00168     ink_assert(new_vs.s.reader_count > 0);
00169     ink_assert(new_vs.s.state != AB_STATE_UNUSED);
00170     ink_assert((uint32_t) read_offset < new_vs.s.offset);
00171 
00172     new_vs.s.reader_count -= 1;
00173   } while (!switch_state(old_vs, new_vs));
00174 
00175   if ((new_vs.s.state == AB_STATE_FLUSH_COMPLETE) && (new_vs.s.reader_count == 0)) {
00176     destroy();
00177   }
00178 
00179   return AB_ERROR_OK;
00180 }
00181 
00182 /*-------------------------------------------------------------------------
00183   -------------------------------------------------------------------------*/
00184 
00185 void
00186 AbstractBuffer::initialize()
00187 {
00188   ink_assert(vs.s.state == AB_STATE_INITIALIZING);
00189   ink_assert(vs.s.writer_count == 0);
00190   ink_assert(vs.s.reader_count == 0);
00191 
00192   if (!unaligned_buffer) {
00193     unaligned_buffer = new char[size + 511];
00194     buffer = (char *) align_pointer_forward(unaligned_buffer, 512);
00195   }
00196 
00197   vs_history[AB_STATE_READ_WRITE] = vs;
00198 
00199   vs.s.offset = 0;
00200   vs.s.state = AB_STATE_READ_WRITE;
00201 }
00202 
00203 /*-------------------------------------------------------------------------
00204   -------------------------------------------------------------------------*/
00205 
00206 void
00207 AbstractBuffer::full()
00208 {
00209   if ((vs.s.state == AB_STATE_READ_ONLY) && (vs.s.writer_count == 0)) {
00210     VolatileState old_vs(vs);
00211     VolatileState new_vs(old_vs);
00212 
00213     while ((new_vs.s.state == AB_STATE_READ_ONLY) && (new_vs.s.writer_count == 0)) {
00214       new_vs.s.state = AB_STATE_FLUSH;
00215       if (switch_state(old_vs, new_vs)) {
00216         vs_history[AB_STATE_FLUSH] = old_vs;
00217         flush();
00218         break;
00219       }
00220 
00221       old_vs = vs;
00222       new_vs = old_vs;
00223     }
00224   }
00225 }
00226 
00227 /*-------------------------------------------------------------------------
00228   -------------------------------------------------------------------------*/
00229 
00230 void
00231 AbstractBuffer::flush()
00232 {
00233   ink_assert(vs.s.state == AB_STATE_FLUSH);
00234   ink_assert(vs.s.writer_count == 0);
00235 }
00236 
00237 /*-------------------------------------------------------------------------
00238   -------------------------------------------------------------------------*/
00239 
00240 void
00241 AbstractBuffer::flush_complete()
00242 {
00243 
00244   VolatileState old_vs;
00245   VolatileState new_vs;
00246 
00247   /* INKqa06826 - Race Condition. Must make sure that setting the new state is
00248      atomic. If there is a context switch in the middle of setting the state to
00249      AB_STATE_FLUSH_COMPLETE, the checkin_read would be lost, the reader_count
00250      will never go to 0, resulting in memory leak */
00251 
00252   do {
00253     old_vs = vs;
00254     new_vs = old_vs;
00255 
00256     ink_assert(vs.s.state == AB_STATE_FLUSH);
00257     ink_assert(vs.s.writer_count == 0);
00258     new_vs.s.state = AB_STATE_FLUSH_COMPLETE;
00259 
00260   } while (!switch_state(old_vs, new_vs));
00261 
00262   vs_history[AB_STATE_FLUSH_COMPLETE] = vs;
00263 
00264   if (vs.s.reader_count == 0) {
00265     destroy();
00266   }
00267 }
00268 
00269 /*-------------------------------------------------------------------------
00270   -------------------------------------------------------------------------*/
00271 
00272 void
00273 AbstractBuffer::destroy()
00274 {
00275   ink_assert(vs.s.state == AB_STATE_FLUSH_COMPLETE);
00276   ink_assert(vs.s.writer_count == 0);
00277   ink_assert(vs.s.reader_count == 0);
00278 
00279   vs_history[AB_STATE_UNUSED] = vs;
00280 
00281   vs.s.offset = 0;
00282   vs.s.state = AB_STATE_UNUSED;
00283 }
00284 
00285 /*-------------------------------------------------------------------------
00286   -------------------------------------------------------------------------*/
00287 
00288 void
00289 AbstractBuffer::clear()
00290 {
00291   if (unaligned_buffer) {
00292     delete[]unaligned_buffer;
00293   }
00294   unaligned_buffer = buffer = NULL;
00295 
00296   vs_history[AB_STATE_UNUSED] = vs;
00297 
00298   vs.s.writer_count = 0;
00299   vs.s.reader_count = 0;
00300   vs.s.offset = 0;
00301   vs.s.state = AB_STATE_UNUSED;
00302 }

Generated by  doxygen 1.7.1